Skip to content

Commit

Permalink
fix(websocket): fix timer blocking writes (#670)
Browse files Browse the repository at this point in the history
An immediate setTimeout was used to unblock the WebSocket write.
Unfortunately, this setTimeout can be throttled by browsers when the
tab is backgrounded.

This can lead to missed pong responses to server pings, which
eventually leads to disconnection.

Related: #649
  • Loading branch information
hyperlink authored and darrachequesne committed Jun 22, 2021
1 parent 52847fd commit f30a10b
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 5 deletions.
12 changes: 11 additions & 1 deletion lib/transports/websocket-constructor.browser.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
const globalThis = require("../globalThis");
const nextTick = (() => {
const isPromiseAvailable =
typeof Promise === "function" && typeof Promise.resolve === "function";
if (isPromiseAvailable) {
return cb => Promise.resolve().then(cb);
} else {
return cb => setTimeout(cb, 0);
}
})();

module.exports = {
WebSocket: globalThis.WebSocket || globalThis.MozWebSocket,
usingBrowserWebSocket: true,
defaultBinaryType: "arraybuffer"
defaultBinaryType: "arraybuffer",
nextTick
};
3 changes: 2 additions & 1 deletion lib/transports/websocket-constructor.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
WebSocket: require("ws"),
usingBrowserWebSocket: false,
defaultBinaryType: "nodebuffer"
defaultBinaryType: "nodebuffer",
nextTick: process.nextTick
};
7 changes: 4 additions & 3 deletions lib/transports/websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const { pick } = require("../util");
const {
WebSocket,
usingBrowserWebSocket,
defaultBinaryType
defaultBinaryType,
nextTick
} = require("./websocket-constructor");

const debug = require("debug")("engine.io-client:websocket");
Expand Down Expand Up @@ -161,10 +162,10 @@ class WS extends Transport {
if (lastPacket) {
// fake drain
// defer to next tick to allow Socket to clear writeBuffer
setTimeout(() => {
nextTick(() => {
this.writable = true;
this.emit("drain");
}, 0);
});
}
});
}
Expand Down

0 comments on commit f30a10b

Please sign in to comment.