close(code, data) {
    if (this.readyState === WebSocket.CLOSED) return;
    if (this.readyState === WebSocket.CONNECTING) {
      const msg = 'WebSocket was closed before the connection was established';
      abortHandshake(this, this._req, msg);
      return;
    }

    if (this.readyState === WebSocket.CLOSING) {
      if (
        this._closeFrameSent &&
        (this._closeFrameReceived || this._receiver._writableState.errorEmitted)
      ) {
        this._socket.end();
      }

      return;
    }

    this._readyState = WebSocket.CLOSING;
    this._sender.close(code, data, !this._isServer, (err) => {
      //
      // This error is handled by the `'error'` listener on the socket. We only
      // want to know if the close frame has been sent here.
      //
      if (err) return;

      this._closeFrameSent = true;

      if (
        this._closeFrameReceived ||
        this._receiver._writableState.errorEmitted
      ) {
        this._socket.end();
      }
    });

    setCloseTimer(this);
  }
Start a closing handshake.

         +----------+   +-----------+   +----------+
    - - -|ws.close()|-->|close frame|-->|ws.close()|- - -
   |     +----------+   +-----------+   +----------+     |
         +----------+   +-----------+         |
CLOSING  |ws.close()|<--|close frame|<--+-----+       CLOSING
         +----------+   +-----------+   |
   |           |                        |   +---+        |
               +------------------------+-->|fin| - - - -
   |         +---+                      |   +---+
    - - - - -|fin|<---------------------+
             +---+

@param {Number} [code] Status code explaining why the connection is closing
@param {(String|Buffer)} [data] The reason why the connection is
    closing
@public