Skip to content

Commit edd6c39

Browse files
committed
When a tab is closed, delete the entry in _hosts
1 parent 337ff6d commit edd6c39

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

.eslintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
parser: 'babel-eslint',
33
extends: 'airbnb-base',
44
env: {
5+
browser: true,
56
worker: true,
67
},
78
rules: {

index.js

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ let messageIDs = 0;
77
const MSGTYPE_QUERY = 0;
88
const MSGTYPE_RESPONSE = 1;
99
const MSGTYPE_HOST_ID = 2;
10-
const MSGTYPES = [MSGTYPE_QUERY, MSGTYPE_RESPONSE, MSGTYPE_HOST_ID];
10+
const MSGTYPE_HOST_CLOSE = 3;
11+
const MSGTYPES = [MSGTYPE_QUERY, MSGTYPE_RESPONSE, MSGTYPE_HOST_ID, MSGTYPE_HOST_CLOSE];
1112

1213
// Inlined from https://github.com/then/is-promise
1314
const isPromise = obj => !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
@@ -63,6 +64,17 @@ class PromiseWorker {
6364

6465
worker.port.addEventListener('message', this._onMessage);
6566
worker.port.start();
67+
68+
// Handle tab close. This isn't perfect, but there is no perfect method
69+
// http://stackoverflow.com/q/13662089/786644 and this should work like
70+
// 99% of the time. It is a memory leak if it fails, but for most use
71+
// cases, it shouldn't be noticeable.
72+
window.addEventListener('beforeunload', () => {
73+
// Prevent firing if we don't know hostID yet
74+
if (this._hostID !== undefined) {
75+
this._postMessageBi([MSGTYPE_HOST_CLOSE, -1, this._hostID]);
76+
}
77+
});
6678
}
6779

6880
this._worker = worker;
@@ -77,6 +89,7 @@ class PromiseWorker {
7789
_postMessageBi(obj: any[], targetHostID: number | void) {
7890
// console.log('_postMessageBi', obj, targetHostID);
7991
if (!this._worker && this._workerType === 'SharedWorker') {
92+
// If targetHostID has been deleted, this will do nothing, which is fine I think
8093
this._hosts.forEach(({ port }, hostID) => {
8194
if (targetHostID === undefined || targetHostID === hostID) {
8295
port.postMessage(obj);
@@ -195,15 +208,26 @@ class PromiseWorker {
195208
callback(errorMsg, result);
196209
} else if (type === MSGTYPE_HOST_ID) {
197210
if (this._worker === undefined) {
198-
throw new Error('hostID can only be sent to a host');
211+
throw new Error('MSGTYPE_HOST_ID can only be sent to a host');
199212
}
200213

201-
if (typeof message[2] !== 'number') {
214+
if (message[2] !== undefined && typeof message[2] !== 'number') {
202215
throw new Error('Invalid hostID');
203216
}
204217
const hostID: number | void = message[2];
205218

206219
this._hostID = hostID;
220+
} else if (type === MSGTYPE_HOST_CLOSE) {
221+
if (this._worker !== undefined) {
222+
throw new Error('MSGTYPE_HOST_CLOSE can only be sent to a worker');
223+
}
224+
225+
if (typeof message[2] !== 'number') {
226+
throw new Error('Invalid hostID');
227+
}
228+
const hostID: number = message[2];
229+
230+
this._hosts.delete(hostID);
207231
}
208232
}
209233
}

0 commit comments

Comments
 (0)