Skip to content

Commit

Permalink
feat: add the "closeOnBeforeunload" option
Browse files Browse the repository at this point in the history
Since [1], the socket is now closed when receiving the "beforeunload"
event in the browser.

This change was meant to fix a discrepancy between Chrome and Firefox
when the user reloads/closes a browser tab: Firefox would close the
connection (and emit a "disconnect" event, at the Socket.IO level), but
not Chrome (see [2]).

But it also closes the connection when there is another "beforeunload"
handler, for example when the user is prompted "are you sure you want
to leave this page?".

Note: calling "stopImmediatePropagation()" was a possible workaround:

```js
window.addEventListener('beforeunload', (event) => {
  event.preventDefault();
  event.stopImmediatePropagation();
  event.returnValue = 'are you sure you want to leave this page?';
});
```

This commit adds a "closeOnBeforeunload" option, which controls whether
a handler is registered for the "beforeunload" event.

Syntax:

```js
const socket = require('engine.io-client')('ws://localhost', {
  closeOnBeforeunload: false // defaults to true
});
```

[1]: ed48b5d
[2]: socketio/socket.io#3639

Related:

- #661
- #658
- socketio/socket.io-client#1451

Reference: https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
  • Loading branch information
darrachequesne committed May 4, 2021
1 parent 9eeed5e commit dcb85e9
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 12 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ Exposed as `eio` in the browser standalone build.
- `requestTimeout` (`Number`): Timeout for xhr-polling requests in milliseconds (`0`)
- **Websocket-only options**
- `protocols` (`Array`): a list of subprotocols (see [MDN reference](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#Subprotocols))
- `closeOnBeforeunload` (`Boolean`): whether to silently close the connection when the [`beforeunload`](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event) event is emitted in the browser (defaults to `true`)
- `send`
- Sends a message to the server
- **Parameters**
Expand Down
30 changes: 18 additions & 12 deletions lib/socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ class Socket extends Emitter {
perMessageDeflate: {
threshold: 1024
},
transportOptions: {}
transportOptions: {},
closeOnBeforeunload: true
},
opts
);
Expand All @@ -91,17 +92,22 @@ class Socket extends Emitter {
this.pingTimeoutTimer = null;

if (typeof addEventListener === "function") {
addEventListener(
"beforeunload",
() => {
if (this.transport) {
// silently close the transport
this.transport.removeAllListeners();
this.transport.close();
}
},
false
);
if (this.opts.closeOnBeforeunload) {
// Firefox closes the connection when the "beforeunload" event is emitted but not Chrome. This event listener
// ensures every browser behaves the same (no "disconnect" event at the Socket.IO level when the page is
// closed/reloaded)
addEventListener(
"beforeunload",
() => {
if (this.transport) {
// silently close the transport
this.transport.removeAllListeners();
this.transport.close();
}
},
false
);
}
if (this.hostname !== "localhost") {
this.offlineEventListener = () => {
this.onClose("transport close");
Expand Down

0 comments on commit dcb85e9

Please sign in to comment.