Эх сурвалжийг харах

Merge pull request #506 from afrokick/refactoring/replaceSelf

Remove XHR as transport for signaling
afrokick 6 жил өмнө
parent
commit
75c405e8f6
8 өөрчлөгдсөн 112 нэмэгдсэн , 350 устгасан
  1. 28 34
      lib/dataconnection.ts
  2. 14 0
      lib/enums.ts
  3. 3 3
      lib/mediaconnection.ts
  4. 10 11
      lib/negotiator.ts
  5. 30 38
      lib/peer.ts
  6. 3 1
      lib/servermessage.ts
  7. 24 207
      lib/socket.ts
  8. 0 56
      lib/util.ts

+ 28 - 34
lib/dataconnection.ts

@@ -4,7 +4,8 @@ import { Reliable } from "reliable";
 import {
   ConnectionType,
   ConnectionEventType,
-  SerializationType
+  SerializationType,
+  ServerMessageType
 } from "./enums";
 import { Peer } from "./peer";
 import { BaseConnection } from "./baseconnection";
@@ -70,12 +71,10 @@ export class DataConnection extends BaseConnection {
       this.dataChannel.binaryType = "arraybuffer";
     }
 
-    const self = this;
-
-    this.dataChannel.onopen = function () {
+    this.dataChannel.onopen = () => {
       util.log("Data channel connection success");
-      self._open = true;
-      self.emit(ConnectionEventType.Open);
+      this._open = true;
+      this.emit(ConnectionEventType.Open);
     };
 
     // Use the Reliable shim for non Firefox browsers
@@ -84,17 +83,17 @@ export class DataConnection extends BaseConnection {
     }
 
     if (this._reliable) {
-      this._reliable.onmessage = function (msg) {
-        self.emit(ConnectionEventType.Data, msg);
+      this._reliable.onmessage = (msg) => {
+        this.emit(ConnectionEventType.Data, msg);
       };
     } else {
-      this.dataChannel.onmessage = function (e) {
-        self._handleDataMessage(e);
+      this.dataChannel.onmessage = (e) => {
+        this._handleDataMessage(e);
       };
     }
-    this.dataChannel.onclose = function (e) {
-      util.log("DataChannel closed for:", self.peer);
-      self.close();
+    this.dataChannel.onclose = (e) => {
+      util.log("DataChannel closed for:", this.peer);
+      this.close();
     };
   }
 
@@ -103,17 +102,15 @@ export class DataConnection extends BaseConnection {
     let data = e.data;
     const datatype = data.constructor;
 
-    if (
-      this.serialization === SerializationType.Binary ||
-      this.serialization === SerializationType.BinaryUTF8
-    ) {
-      if (datatype === Blob) {
-        const self = this;
+    const isBinarySerialization = this.serialization === SerializationType.Binary ||
+      this.serialization === SerializationType.BinaryUTF8;
 
+    if (isBinarySerialization) {
+      if (datatype === Blob) {
         // Datatype should never be blob
-        util.blobToArrayBuffer(data, function (ab) {
+        util.blobToArrayBuffer(data, (ab) => {
           data = util.unpack(ab);
-          self.emit(ConnectionEventType.Data, data);
+          this.emit(ConnectionEventType.Data, data);
         });
         return;
       } else if (datatype === ArrayBuffer) {
@@ -209,18 +206,16 @@ export class DataConnection extends BaseConnection {
         return;
       }
 
-      const self = this;
-
       // DataChannel currently only supports strings.
       if (!util.supports.sctp) {
-        util.blobToBinaryString(blob, function (str) {
-          self._bufferedSend(str);
+        util.blobToBinaryString(blob, (str) => {
+          this._bufferedSend(str);
         });
       } else if (!util.supports.binaryBlob) {
         // We only do this if we really need to (e.g. blobs are not supported),
         // because this conversion is costly.
-        util.blobToArrayBuffer(blob, function (ab) {
-          self._bufferedSend(ab);
+        util.blobToArrayBuffer(blob, (ab) => {
+          this._bufferedSend(ab);
         });
       } else {
         this._bufferedSend(blob);
@@ -244,13 +239,12 @@ export class DataConnection extends BaseConnection {
     } catch (e) {
       this._buffering = true;
 
-      const self = this;
-
-      setTimeout(function () {
+      setTimeout(() => {
         // Try again.
-        self._buffering = false;
-        self._tryBuffer();
+        this._buffering = false;
+        this._tryBuffer();
       }, 100);
+
       return false;
     }
 
@@ -284,13 +278,13 @@ export class DataConnection extends BaseConnection {
     const payload = message.payload;
 
     switch (message.type) {
-      case "ANSWER":
+      case ServerMessageType.Answer:
         this._peerBrowser = payload.browser;
 
         // Forward to negotiator
         Negotiator.handleSDP(message.type, this, payload.sdp);
         break;
-      case "CANDIDATE":
+      case ServerMessageType.Candidate:
         Negotiator.handleCandidate(this, payload.candidate);
         break;
       default:

+ 14 - 0
lib/enums.ts

@@ -47,3 +47,17 @@ export enum SocketEventType {
   Error = "error",
   Close = "close"
 }
+
+export enum ServerMessageType {
+  Heartbeat = "HEARTBEAT",
+  Candidate = "CANDIDATE",
+  Offer = "OFFER",
+  Answer = "ANSWER",
+  Open = "OPEN", // The connection to the server is open.
+  Error = "ERROR", // Server error.
+  IdTaken = "ID-TAKEN", // The selected ID is taken.
+  InvalidKey = "INVALID-KEY", // The given API key cannot be found.
+  Leave = "LEAVE", // Another peer has closed its connection to this peer.
+  Expire = "EXPIRE" // The offer sent to a peer has expired without response.
+
+}

+ 3 - 3
lib/mediaconnection.ts

@@ -1,6 +1,6 @@
 import { util } from "./util";
 import Negotiator from "./negotiator";
-import { ConnectionType, ConnectionEventType } from "./enums";
+import { ConnectionType, ConnectionEventType, ServerMessageType } from "./enums";
 import { Peer } from "./peer";
 import { BaseConnection } from "./baseconnection";
 import { ServerMessage } from "./servermessage";
@@ -46,12 +46,12 @@ export class MediaConnection extends BaseConnection {
     const payload = message.payload;
 
     switch (message.type) {
-      case "ANSWER":
+      case ServerMessageType.Answer:
         // Forward to negotiator
         Negotiator.handleSDP(type, this, payload.sdp);
         this._open = true;
         break;
-      case "CANDIDATE":
+      case ServerMessageType.Candidate:
         Negotiator.handleCandidate(this, payload.candidate);
         break;
       default:

+ 10 - 11
lib/negotiator.ts

@@ -7,9 +7,8 @@ import {
 import * as Reliable from "reliable";
 import { MediaConnection } from "./mediaconnection";
 import { DataConnection } from "./dataconnection";
-import { ConnectionType, PeerErrorType, ConnectionEventType } from "./enums";
+import { ConnectionType, PeerErrorType, ConnectionEventType, ServerMessageType } from "./enums";
 import { BaseConnection } from "./baseconnection";
-import { utils } from "mocha";
 
 /**
  * Manages all negotiations between Peers.
@@ -129,11 +128,11 @@ class Negotiator {
     // ICE CANDIDATES.
     util.log("Listening for ICE candidates.");
 
-    peerConnection.onicecandidate = function (evt) {
+    peerConnection.onicecandidate = (evt) => {
       if (evt.candidate) {
         util.log("Received ICE candidates for:", peerId);
         provider.socket.send({
-          type: "CANDIDATE",
+          type: ServerMessageType.Candidate,
           payload: {
             candidate: evt.candidate,
             type: connectionType,
@@ -144,7 +143,7 @@ class Negotiator {
       }
     };
 
-    peerConnection.oniceconnectionstatechange = function () {
+    peerConnection.oniceconnectionstatechange = () => {
       switch (peerConnection.iceConnectionState) {
         case "failed":
           util.log(
@@ -177,7 +176,7 @@ class Negotiator {
     util.log("Listening for data channel");
     // Fired between offer and answer, so options should already be saved
     // in the options hash.
-    peerConnection.ondatachannel = function (evt) {
+    peerConnection.ondatachannel = (evt) => {
       util.log("Received data channel");
 
       const dataChannel = evt.channel;
@@ -190,8 +189,8 @@ class Negotiator {
 
     // MEDIACONNECTION.
     util.log("Listening for remote stream");
-    const self = this;
-    peerConnection.ontrack = function (evt) {
+
+    peerConnection.ontrack = (evt) => {
       util.log("Received remote stream");
 
       const stream = evt.streams[0];
@@ -200,7 +199,7 @@ class Negotiator {
       if (connection.type === ConnectionType.Media) {
         const mediaConnection = <MediaConnection>connection;
 
-        self._addStreamToMediaConnection(stream, mediaConnection);
+        this._addStreamToMediaConnection(stream, mediaConnection);
       }
     };
   }
@@ -273,7 +272,7 @@ class Negotiator {
         }
 
         connection.provider.socket.send({
-          type: "OFFER",
+          type: ServerMessageType.Offer,
           payload,
           dst: connection.peer
         });
@@ -313,7 +312,7 @@ class Negotiator {
         util.log(`Set localDescription:`, answer, `for:${connection.peer}`);
 
         connection.provider.socket.send({
-          type: "ANSWER",
+          type: ServerMessageType.Answer,
           payload: {
             sdp: answer,
             type: connection.type,

+ 30 - 38
lib/peer.ts

@@ -8,7 +8,8 @@ import {
   PeerErrorType,
   PeerEventType,
   SocketEventType,
-  SerializationType
+  SerializationType,
+  ServerMessageType
 } from "./enums";
 import { BaseConnection } from "./baseconnection";
 import { ServerMessage } from "./servermessage";
@@ -19,7 +20,6 @@ class PeerOptions implements PeerJSOption {
   debug: number; // 1: Errors, 2: Warnings, 3: All logs
   host: string;
   port: number;
-  wsport: number;
   path: string;
   key: string;
   token: string;
@@ -163,31 +163,28 @@ export class Peer extends EventEmitter {
       this._options.port,
       this._options.path,
       this._options.key,
-      this._options.wsport
     );
 
-    const self = this;
-
     this.socket.on(SocketEventType.Message, data => {
-      self._handleMessage(data);
+      this._handleMessage(data);
     });
 
     this.socket.on(SocketEventType.Error, error => {
-      self._abort(PeerErrorType.SocketError, error);
+      this._abort(PeerErrorType.SocketError, error);
     });
 
     this.socket.on(SocketEventType.Disconnected, () => {
       // If we haven't explicitly disconnected, emit error and disconnect.
-      if (!self.disconnected) {
-        self.emitError(PeerErrorType.Network, "Lost connection to server.");
-        self.disconnect();
+      if (!this.disconnected) {
+        this.emitError(PeerErrorType.Network, "Lost connection to server.");
+        this.disconnect();
       }
     });
 
-    this.socket.on(SocketEventType.Close, function () {
+    this.socket.on(SocketEventType.Close, () => {
       // If we haven't explicitly disconnected, emit error.
-      if (!self.disconnected) {
-        self._abort(
+      if (!this.disconnected) {
+        this._abort(
           PeerErrorType.SocketClosed,
           "Underlying socket is already closed."
         );
@@ -208,36 +205,33 @@ export class Peer extends EventEmitter {
     const peerId = message.src;
 
     switch (type) {
-      case "OPEN": // The connection to the server is open.
+      case ServerMessageType.Open: // The connection to the server is open.
         this.emit(PeerEventType.Open, this.id);
         this._open = true;
         break;
-      case "ERROR": // Server error.
+      case ServerMessageType.Error: // Server error.
         this._abort(PeerErrorType.ServerError, payload.msg);
         break;
-      case "ID-TAKEN": // The selected ID is taken.
+      case ServerMessageType.IdTaken: // The selected ID is taken.
         this._abort(PeerErrorType.UnavailableID, `ID "${this.id}" is taken`);
         break;
-      case "INVALID-KEY": // The given API key cannot be found.
+      case ServerMessageType.InvalidKey: // The given API key cannot be found.
         this._abort(
           PeerErrorType.InvalidKey,
           `API KEY "${this._options.key}" is invalid`
         );
         break;
-
-      //
-      case "LEAVE": // Another peer has closed its connection to this peer.
+      case ServerMessageType.Leave: // Another peer has closed its connection to this peer.
         util.log("Received leave message from", peerId);
         this._cleanupPeer(peerId);
         break;
-
-      case "EXPIRE": // The offer sent to a peer has expired without response.
+      case ServerMessageType.Expire: // The offer sent to a peer has expired without response.
         this.emitError(
           PeerErrorType.PeerUnavailable,
           "Could not connect to peer " + peerId
         );
         break;
-      case "OFFER": {
+      case ServerMessageType.Offer: {
         // we should consider switching this to CALL/CONNECT, but this is the least breaking option.
         const connectionId = payload.connectionId;
         let connection = this.getConnection(peerId, connectionId);
@@ -412,10 +406,9 @@ export class Peer extends EventEmitter {
   }
 
   private _delayedAbort(type: PeerErrorType, message): void {
-    const self = this;
-    util.setZeroTimeout(function () {
-      self._abort(type, message);
-    });
+    setTimeout(() => {
+      this._abort(type, message);
+    }, 0);
   }
 
   /**
@@ -490,20 +483,19 @@ export class Peer extends EventEmitter {
    *  disconnected. It also cannot reconnect to the server.
    */
   disconnect(): void {
-    const self = this;
-    util.setZeroTimeout(function () {
-      if (!self.disconnected) {
-        self._disconnected = true;
-        self._open = false;
-        if (self.socket) {
-          self.socket.close();
+    setTimeout(() => {
+      if (!this.disconnected) {
+        this._disconnected = true;
+        this._open = false;
+        if (this.socket) {
+          this.socket.close();
         }
 
-        self.emit(PeerEventType.Disconnected, self.id);
-        self._lastServerId = self.id;
-        self._id = null;
+        this.emit(PeerEventType.Disconnected, this.id);
+        this._lastServerId = this.id;
+        this._id = null;
       }
-    });
+    }, 0);
   }
 
   /** Attempts to reconnect with the same ID. */

+ 3 - 1
lib/servermessage.ts

@@ -1,5 +1,7 @@
+import { ServerMessageType } from "./enums";
+
 export class ServerMessage {
-  type: string;
+  type: ServerMessageType;
   payload: any;
   src: string;
 }

+ 24 - 207
lib/socket.ts

@@ -1,107 +1,20 @@
 import { util } from "./util";
 import { EventEmitter } from "eventemitter3";
-import { SocketEventType } from "./enums";
-
-class HttpRequest {
-  index = 1;
-  readonly buffer: number[] = [];
-  previousRequest: HttpRequest;
-  private _xmlHttpRequest = new XMLHttpRequest();
-
-  private _onError = sender => { };
-  private _onSuccess = sender => { };
-
-  set onError(handler) {
-    this._onError = handler;
-  }
-
-  set onSuccess(handler) {
-    this._onSuccess = handler;
-  }
-
-  constructor(readonly streamIndex: number, private readonly _httpUrl: string) {
-    const self = this;
-
-    this._xmlHttpRequest.onerror = () => {
-      self._onError(self);
-    };
-
-    this._xmlHttpRequest.onreadystatechange = () => {
-      if (self.needsClearPreviousRequest()) {
-        self.clearPreviousRequest();
-      } else if (self.isSuccess()) {
-        self._onSuccess(self);
-      }
-    };
-  }
-
-  send(): void {
-    this._xmlHttpRequest.open(
-      "post",
-      this._httpUrl + "/id?i=" + this.streamIndex,
-      true
-    );
-    this._xmlHttpRequest.send(null);
-  }
-
-  abort(): void {
-    this._xmlHttpRequest.abort();
-    this._xmlHttpRequest = null;
-  }
-
-  isSuccess(): boolean {
-    return (
-      this._xmlHttpRequest.readyState > 2 &&
-      this._xmlHttpRequest.status === 200 &&
-      !!this._xmlHttpRequest.responseText
-    );
-  }
-
-  needsClearPreviousRequest(): boolean {
-    return this._xmlHttpRequest.readyState === 2 && !!this.previousRequest;
-  }
-
-  clearPreviousRequest(): void {
-    if (!this.previousRequest) return;
-
-    this.previousRequest.abort();
-    this.previousRequest = null;
-  }
-
-  getMessages(): string[] {
-    return this._xmlHttpRequest.responseText.split("\n");
-  }
-
-  hasBufferedIndices(): boolean {
-    return this.buffer.length > 0;
-  }
-
-  popBufferedIndex(): number {
-    return this.buffer.shift();
-  }
-
-  pushIndexToBuffer(index: number) {
-    this.buffer.push(index);
-  }
-}
+import { SocketEventType, ServerMessageType } from "./enums";
 
 /**
- * An abstraction on top of WebSockets and XHR streaming to provide fastest
+ * An abstraction on top of WebSockets to provide fastest
  * possible connection for peers.
  */
 export class Socket extends EventEmitter {
-  private readonly HTTP_TIMEOUT = 25000;//ms
   private readonly WEB_SOCKET_PING_INTERVAL = 20000;//ms
 
   private _disconnected = false;
   private _id: string;
   private _messagesQueue: Array<any> = [];
-  private _httpUrl: string;
   private _wsUrl: string;
   private _socket: WebSocket;
   private _wsPingTimer: any;
-  private _httpRequest: HttpRequest;
-  private _timeout: any;
 
   constructor(
     secure: any,
@@ -109,25 +22,20 @@ export class Socket extends EventEmitter {
     port: number,
     path: string,
     key: string,
-    wsport = port
   ) {
     super();
 
-    const httpProtocol = secure ? "https://" : "http://";
     const wsProtocol = secure ? "wss://" : "ws://";
 
-    this._httpUrl = httpProtocol + host + ":" + port + path + key;
-    this._wsUrl = wsProtocol + host + ":" + wsport + path + "peerjs?key=" + key;
+    this._wsUrl = wsProtocol + host + ":" + port + path + "peerjs?key=" + key;
   }
 
   /** Check in with ID or get one from server. */
   start(id: string, token: string): void {
     this._id = id;
 
-    this._httpUrl += "/" + id + "/" + token;
     this._wsUrl += "&id=" + id + "&token=" + token;
 
-    this._startXhrStream();
     this._startWebSocket();
   }
 
@@ -139,9 +47,7 @@ export class Socket extends EventEmitter {
 
     this._socket = new WebSocket(this._wsUrl);
 
-    const self = this;
-
-    this._socket.onmessage = function (event) {
+    this._socket.onmessage = (event) => {
       let data;
 
       try {
@@ -150,56 +56,32 @@ export class Socket extends EventEmitter {
         util.log("Invalid server message", event.data);
         return;
       }
-      self.emit(SocketEventType.Message, data);
+
+      this.emit(SocketEventType.Message, data);
     };
 
-    this._socket.onclose = function (event) {
+    this._socket.onclose = (event) => {
       util.log("Socket closed.", event);;
 
-      self._disconnected = true;
-      self.emit(SocketEventType.Disconnected);
+      this._disconnected = true;
+      clearTimeout(this._wsPingTimer);
+
+      this.emit(SocketEventType.Disconnected);
     };
 
     // Take care of the queue of connections if necessary and make sure Peer knows
     // socket is open.
-    this._socket.onopen = function () {
-      if (self._timeout) {
-        clearTimeout(self._timeout);
-        setTimeout(function () {
-          self._httpRequest.abort();
-          self._httpRequest = null;
-        }, 5000);
-      }
+    this._socket.onopen = () => {
+      this._sendQueuedMessages();
 
-      self._sendQueuedMessages();
       util.log("Socket open");
 
-      self._wsPingTimer = setTimeout(function () { self._sendHeartbeat() }, self.WEB_SOCKET_PING_INTERVAL);
+      this._scheduleHeartbeat();
     };
   }
 
-  /** Start XHR streaming. */
-  private _startXhrStream(streamIndex: number = 0) {
-    const newRequest = new HttpRequest(streamIndex, this._httpUrl);
-    this._httpRequest = newRequest;
-
-    newRequest.onError = () => {
-      // If we get an error, likely something went wrong.
-      // Stop streaming.
-      clearTimeout(this._timeout);
-      this.emit(SocketEventType.Disconnected);
-    };
-
-    newRequest.onSuccess = () => {
-      this._handleStream(newRequest);
-    };
-
-    try {
-      newRequest.send();
-      this._setHTTPTimeout();
-    } catch (e) {
-      util.log("XMLHttpRequest not available; defaulting to WebSockets");
-    }
+  private _scheduleHeartbeat(): void {
+    this._wsPingTimer = setTimeout(() => { this._sendHeartbeat() }, this.WEB_SOCKET_PING_INTERVAL);
   }
 
   private _sendHeartbeat(): void {
@@ -208,71 +90,11 @@ export class Socket extends EventEmitter {
       return;
     }
 
-    const data = { type: 'HEARTBEAT' };
-    const message = JSON.stringify(data);
-    this._socket.send(message);
-
-    const self = this;
-
-    this._wsPingTimer = setTimeout(function () { self._sendHeartbeat() }, this.WEB_SOCKET_PING_INTERVAL);
-  }
-
-  /** Handles onreadystatechange response as a stream. */
-  private _handleStream(httpRequest: HttpRequest) {
-    // 3 and 4 are loading/done state. All others are not relevant.
-    const messages = httpRequest.getMessages();
-
-    // Check to see if anything needs to be processed on buffer.
+    const message = JSON.stringify({ type: ServerMessageType.Heartbeat });
 
-    while (httpRequest.hasBufferedIndices()) {
-      const index = httpRequest.popBufferedIndex();
-      let bufferedMessage = messages[index];
-
-      try {
-        bufferedMessage = JSON.parse(bufferedMessage);
-      } catch (e) {
-        //TODO should we need to put it back?
-        httpRequest.buffer.unshift(index);
-        break;
-      }
-
-      this.emit(SocketEventType.Message, bufferedMessage);
-    }
-
-    let message = messages[httpRequest.index];
-
-    if (message) {
-      httpRequest.index += 1;
-      // Buffering--this message is incomplete and we'll get to it next time.
-      // This checks if the httpResponse ended in a `\n`, in which case the last
-      // element of messages should be the empty string.
-      if (httpRequest.index === messages.length) {
-        httpRequest.pushIndexToBuffer(httpRequest.index - 1);
-      } else {
-        try {
-          message = JSON.parse(message);
-        } catch (e) {
-          util.log("Invalid server message", message);
-          return;
-        }
-        this.emit(SocketEventType.Message, message);
-      }
-    }
-  }
+    this._socket.send(message);
 
-  private _setHTTPTimeout() {
-    const self = this;
-
-    this._timeout = setTimeout(function () {
-      if (!self._wsOpen()) {
-        const oldHttp = self._httpRequest;
-        self._startXhrStream(oldHttp.streamIndex + 1);
-        self._httpRequest.previousRequest = oldHttp;
-      } else {
-        self._httpRequest.abort();
-        self._httpRequest = null;
-      }
-    }, this.HTTP_TIMEOUT);
+    this._scheduleHeartbeat();
   }
 
   /** Is the websocket currently open? */
@@ -282,7 +104,6 @@ export class Socket extends EventEmitter {
 
   /** Send queued messages. */
   private _sendQueuedMessages(): void {
-    //TODO is it ok?
     //Create copy of queue and clear it,
     //because send method push the message back to queue if smth will go wrong
     const copiedQueue = [...this._messagesQueue];
@@ -311,17 +132,13 @@ export class Socket extends EventEmitter {
       return;
     }
 
+    if (!this._wsOpen()) {
+      return;
+    }
+
     const message = JSON.stringify(data);
 
-    if (this._wsOpen()) {
-      this._socket.send(message);
-    } else {
-      const http = new XMLHttpRequest();
-      const url = this._httpUrl + "/" + data.type.toLowerCase();
-      http.open("post", url, true);
-      http.setRequestHeader("Content-Type", "application/json");
-      http.send(message);
-    }
+    this._socket.send(message);
   }
 
   close(): void {

+ 0 - 56
lib/util.ts

@@ -210,27 +210,6 @@ export class util {
     return !id || /^[A-Za-z0-9]+(?:[ _-][A-Za-z0-9]+)*$/.test(id);
   }
 
-  static inherits(ctor, superCtor): void {
-    ctor.super_ = superCtor;
-    ctor.prototype = Object.create(superCtor.prototype, {
-      constructor: {
-        value: ctor,
-        enumerable: false,
-        writable: true,
-        configurable: true
-      }
-    });
-  }
-
-  static extend(dest, source): any {
-    for (let key in source) {
-      if (source.hasOwnProperty(key)) {
-        dest[key] = source[key];
-      }
-    }
-    return dest;
-  }
-
   static pack = BinaryPack.pack;
   static unpack = BinaryPack.unpack;
 
@@ -255,41 +234,6 @@ export class util {
   static warn(...rest): void { }
   static error(...rest): void { }
 
-  static setZeroTimeout = (global => {
-    const timeouts = [];
-    const messageName = "zero-timeout-message";
-
-    // Like setTimeout, but only takes a function argument.	 There's
-    // no time argument (always zero) and no arguments (you have to
-    // use a closure).
-    function setZeroTimeoutPostMessage(fn) {
-      timeouts.push(fn);
-      global.postMessage(messageName, "*");
-    }
-
-    function handleMessage(event) {
-      if (event.source === global && event.data === messageName) {
-        if (event.stopPropagation) {
-          event.stopPropagation();
-        }
-        if (timeouts.length) {
-          timeouts.shift()();
-        }
-      }
-    }
-
-    if (global.addEventListener) {
-      global.addEventListener("message", handleMessage, true);
-    }
-    // @ts-ignore
-    else if (global.attachEvent) {
-      // @ts-ignore
-      global.attachEvent("onmessage", handleMessage);
-    }
-
-    return setZeroTimeoutPostMessage;
-  })(window);
-
   // Binary stuff
 
   private static _dataCount = 1;