promise-worker-bi 4.1.1 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/{esmodules.mjs → index.js} +56 -110
- package/dist/test/test.js +1838 -0
- package/dist/test/worker-bidirectional-echo.js +1180 -0
- package/dist/test/worker-echo-custom-2.js +265 -0
- package/dist/test/worker-echo-custom.js +265 -0
- package/dist/test/worker-echo.js +258 -0
- package/dist/test/worker-empty.js +257 -0
- package/dist/test/worker-error-async.js +260 -0
- package/dist/test/worker-error-sync.js +258 -0
- package/dist/test/worker-host-echo-custom.js +1194 -0
- package/dist/test/worker-host-echo-multiple.js +1193 -0
- package/dist/test/worker-host-echo.js +1175 -0
- package/dist/test/worker-host-empty.js +1183 -0
- package/dist/test/worker-host-error-async.js +1180 -0
- package/dist/test/worker-host-error-outside-response.js +260 -0
- package/dist/test/worker-host-error-sync.js +1180 -0
- package/dist/test/worker-host-ping.js +1175 -0
- package/dist/test/worker-host-transferable.js +1185 -0
- package/dist/test/worker-hostid.js +259 -0
- package/dist/test/worker-pong-promise.js +258 -0
- package/dist/test/worker-pong.js +258 -0
- package/dist/{commonjs.js → test/worker-shared.js} +52 -222
- package/dist/test/worker-transferable.js +1188 -0
- package/package.json +73 -73
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
type ErrorCallback = (a: Error) => void;
|
|
2
|
+
type QueryCallback = (a: any[], b: number | undefined) => any;
|
|
3
3
|
declare abstract class PWBBase {
|
|
4
4
|
_callbacks: Map<number, (a: Error | null, b: any) => void>;
|
|
5
5
|
_queryCallback: QueryCallback;
|
|
@@ -4,96 +4,82 @@ const MSGTYPE_RESPONSE = 1;
|
|
|
4
4
|
const MSGTYPE_HOST_ID = 2;
|
|
5
5
|
const MSGTYPE_HOST_CLOSE = 3;
|
|
6
6
|
const MSGTYPE_WORKER_ERROR = 4;
|
|
7
|
-
const MSGTYPES = [MSGTYPE_QUERY, MSGTYPE_RESPONSE, MSGTYPE_HOST_ID, MSGTYPE_HOST_CLOSE, MSGTYPE_WORKER_ERROR];
|
|
7
|
+
const MSGTYPES = [MSGTYPE_QUERY, MSGTYPE_RESPONSE, MSGTYPE_HOST_ID, MSGTYPE_HOST_CLOSE, MSGTYPE_WORKER_ERROR];
|
|
8
8
|
|
|
9
|
+
// Inlined from https://github.com/then/is-promise
|
|
9
10
|
const isPromise = obj => !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
|
|
10
|
-
|
|
11
11
|
const toFakeError = error => {
|
|
12
12
|
const fakeError = {
|
|
13
13
|
name: error.name,
|
|
14
14
|
message: error.message
|
|
15
15
|
};
|
|
16
|
-
|
|
17
16
|
if (typeof error.stack === "string") {
|
|
18
17
|
fakeError.stack = error.stack;
|
|
19
|
-
}
|
|
20
|
-
// @ts-expect-error
|
|
21
|
-
|
|
18
|
+
}
|
|
22
19
|
|
|
20
|
+
// These are non-standard properties, I think only in some versions of Firefox
|
|
21
|
+
// @ts-expect-error
|
|
23
22
|
if (typeof error.fileName === "string") {
|
|
24
23
|
// @ts-expect-error
|
|
25
24
|
fakeError.fileName = error.fileName;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
}
|
|
26
|
+
// @ts-expect-error
|
|
29
27
|
if (typeof error.columnNumber === "number") {
|
|
30
28
|
// @ts-expect-error
|
|
31
29
|
fakeError.columnNumber = error.columnNumber;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
}
|
|
31
|
+
// @ts-expect-error
|
|
35
32
|
if (typeof error.lineNumber === "number") {
|
|
36
33
|
// @ts-expect-error
|
|
37
34
|
fakeError.lineNumber = error.lineNumber;
|
|
38
35
|
}
|
|
39
|
-
|
|
40
36
|
return fakeError;
|
|
41
|
-
};
|
|
42
|
-
|
|
37
|
+
};
|
|
43
38
|
|
|
39
|
+
// Object rather than FakeError for convenience
|
|
44
40
|
const fromFakeError = fakeError => {
|
|
45
41
|
const error = new Error();
|
|
46
42
|
return Object.assign(error, fakeError);
|
|
47
43
|
};
|
|
48
|
-
|
|
49
44
|
const logError = err => {
|
|
50
45
|
// Logging in the console makes debugging in the worker easier
|
|
51
|
-
|
|
52
|
-
/* eslint-disable no-console */
|
|
53
46
|
console.error("Error in Worker:");
|
|
54
47
|
console.error(err); // Safari needs it on new line
|
|
55
|
-
|
|
56
|
-
/* eslint-enable no-console */
|
|
57
48
|
};
|
|
58
|
-
|
|
59
49
|
class PWBBase {
|
|
60
50
|
constructor() {
|
|
61
51
|
// console.log('constructor', worker);
|
|
62
|
-
this._callbacks = new Map();
|
|
63
|
-
|
|
64
|
-
this._queryCallback = () => {}; // @ts-expect-error
|
|
65
|
-
|
|
52
|
+
this._callbacks = new Map();
|
|
53
|
+
this._queryCallback = () => {};
|
|
66
54
|
|
|
55
|
+
// @ts-expect-error
|
|
67
56
|
this._onMessage = this._onMessage.bind(this);
|
|
68
57
|
}
|
|
69
|
-
|
|
70
58
|
register(cb) {
|
|
71
59
|
// console.log('register', cb);
|
|
72
60
|
this._queryCallback = cb;
|
|
73
|
-
}
|
|
61
|
+
}
|
|
74
62
|
|
|
63
|
+
// From worker, 2nd param could be hostID if sending to specific host. From UI, 2nd param could be an array of transferable objects
|
|
75
64
|
|
|
76
65
|
_postResponse(messageID, error, result, hostID) {
|
|
77
66
|
// console.log('_postResponse', messageID, error, result);
|
|
78
67
|
if (error) {
|
|
79
68
|
logError(error);
|
|
80
|
-
|
|
81
69
|
this._postMessage([MSGTYPE_RESPONSE, messageID, toFakeError(error)], hostID);
|
|
82
70
|
} else {
|
|
83
71
|
// Hackily identify when message contains transferable objects
|
|
84
|
-
if (typeof result === "object" && result !== null &&
|
|
72
|
+
if (typeof result === "object" && result !== null && Object.hasOwn(result, "message") && Object.hasOwn(result, "_PWB_TRANSFER")) {
|
|
85
73
|
this._postMessage([MSGTYPE_RESPONSE, messageID, null, result.message], hostID, result._PWB_TRANSFER);
|
|
86
74
|
} else {
|
|
87
75
|
this._postMessage([MSGTYPE_RESPONSE, messageID, null, result], hostID);
|
|
88
76
|
}
|
|
89
77
|
}
|
|
90
78
|
}
|
|
91
|
-
|
|
92
79
|
_handleQuery(messageID, query, hostID) {
|
|
93
80
|
// console.log('_handleQuery', messageID, query);
|
|
94
81
|
try {
|
|
95
82
|
const result = this._queryCallback(query, hostID);
|
|
96
|
-
|
|
97
83
|
if (!isPromise(result)) {
|
|
98
84
|
this._postResponse(messageID, null, result, hostID);
|
|
99
85
|
} else {
|
|
@@ -106,78 +92,61 @@ class PWBBase {
|
|
|
106
92
|
} catch (err) {
|
|
107
93
|
this._postResponse(messageID, err);
|
|
108
94
|
}
|
|
109
|
-
}
|
|
110
|
-
|
|
95
|
+
}
|
|
111
96
|
|
|
97
|
+
// Either return messageID and type if further processing is needed, or undefined otherwise
|
|
112
98
|
_onMessageCommon(e) {
|
|
113
|
-
// eslint-disable-line no-undef
|
|
114
99
|
// console.log('_onMessage', e.data);
|
|
115
100
|
const message = e.data;
|
|
116
|
-
|
|
117
101
|
if (!Array.isArray(message) || message.length < 3 || message.length > 4) {
|
|
118
102
|
return; // Ignore - this message is not for us
|
|
119
103
|
}
|
|
120
|
-
|
|
121
104
|
if (typeof message[0] !== "number" || MSGTYPES.indexOf(message[0]) < 0) {
|
|
122
105
|
throw new Error("Invalid messageID");
|
|
123
106
|
}
|
|
124
|
-
|
|
125
107
|
const type = message[0];
|
|
126
|
-
|
|
127
108
|
if (typeof message[1] !== "number") {
|
|
128
109
|
throw new Error("Invalid messageID");
|
|
129
110
|
}
|
|
130
|
-
|
|
131
111
|
const messageID = message[1];
|
|
132
|
-
|
|
133
112
|
if (type === MSGTYPE_QUERY) {
|
|
134
113
|
const query = message[2];
|
|
135
|
-
|
|
136
114
|
if (typeof message[3] !== "number" && message[3] !== undefined) {
|
|
137
115
|
throw new Error("Invalid hostID");
|
|
138
116
|
}
|
|
139
|
-
|
|
140
117
|
const hostID = message[3];
|
|
141
|
-
|
|
142
118
|
this._handleQuery(messageID, query, hostID);
|
|
143
|
-
|
|
144
119
|
return;
|
|
145
120
|
}
|
|
146
|
-
|
|
147
121
|
if (type === MSGTYPE_RESPONSE) {
|
|
148
122
|
if (message[2] !== null && typeof message[2] !== "object") {
|
|
149
123
|
throw new Error("Invalid error");
|
|
150
124
|
}
|
|
151
|
-
|
|
152
125
|
const error = message[2] === null ? null : fromFakeError(message[2]);
|
|
153
126
|
const result = message[3];
|
|
154
|
-
|
|
155
127
|
const callback = this._callbacks.get(messageID);
|
|
156
|
-
|
|
157
128
|
if (callback === undefined) {
|
|
158
129
|
// Ignore - user might have created multiple PromiseWorkers.
|
|
159
130
|
// This message is not for us.
|
|
160
131
|
return;
|
|
161
132
|
}
|
|
162
|
-
|
|
163
133
|
this._callbacks.delete(messageID);
|
|
164
|
-
|
|
165
134
|
callback(error, result);
|
|
166
135
|
return;
|
|
167
136
|
}
|
|
168
|
-
|
|
169
137
|
return {
|
|
170
138
|
message,
|
|
171
139
|
type
|
|
172
140
|
};
|
|
173
141
|
}
|
|
174
|
-
|
|
175
142
|
}
|
|
176
|
-
|
|
177
143
|
class PWBHost extends PWBBase {
|
|
178
144
|
// Only defined on host
|
|
145
|
+
|
|
179
146
|
constructor(worker) {
|
|
180
|
-
super();
|
|
147
|
+
super();
|
|
148
|
+
|
|
149
|
+
// The following if statement used to check `worker instanceof Worker` but I have recieved
|
|
181
150
|
// reports that in some weird cases, Safari will inappropriately return false for that, even
|
|
182
151
|
// in obvious cases like:
|
|
183
152
|
//
|
|
@@ -187,21 +156,23 @@ class PWBHost extends PWBBase {
|
|
|
187
156
|
//
|
|
188
157
|
// So instead, let's do this test for worker.port which only exists on shared workers.
|
|
189
158
|
// @ts-expect-error
|
|
190
|
-
|
|
191
159
|
if (worker.port === undefined) {
|
|
192
|
-
this._workerType = "Worker";
|
|
160
|
+
this._workerType = "Worker";
|
|
193
161
|
|
|
162
|
+
// @ts-expect-error
|
|
194
163
|
worker.addEventListener("message", this._onMessage);
|
|
195
164
|
} else {
|
|
196
|
-
this._workerType = "SharedWorker";
|
|
165
|
+
this._workerType = "SharedWorker";
|
|
197
166
|
|
|
198
|
-
|
|
167
|
+
// @ts-expect-error - it doesn't know if _worker is Worker or SharedWorker, but I do
|
|
168
|
+
worker.port.addEventListener("message", this._onMessage);
|
|
169
|
+
// @ts-expect-error - it doesn't know if _worker is Worker or SharedWorker, but I do
|
|
170
|
+
worker.port.start();
|
|
199
171
|
|
|
200
|
-
|
|
172
|
+
// Handle tab close. This isn't perfect, but there is no perfect method
|
|
201
173
|
// http://stackoverflow.com/q/13662089/786644 and this should work like
|
|
202
174
|
// 99% of the time. It is a memory leak if it fails, but for most use
|
|
203
175
|
// cases, it shouldn't be noticeable.
|
|
204
|
-
|
|
205
176
|
window.addEventListener("beforeunload", () => {
|
|
206
177
|
// Prevent firing if we don't know hostID yet
|
|
207
178
|
if (this._hostID !== undefined) {
|
|
@@ -209,22 +180,20 @@ class PWBHost extends PWBBase {
|
|
|
209
180
|
}
|
|
210
181
|
});
|
|
211
182
|
}
|
|
212
|
-
|
|
213
183
|
this._worker = worker;
|
|
214
184
|
this._hostIDQueue = [];
|
|
215
185
|
}
|
|
216
|
-
|
|
217
186
|
registerError(cb) {
|
|
218
187
|
// console.log('registerError', cb);
|
|
219
|
-
this._errorCallback = cb;
|
|
220
|
-
// (Chrome) do nothing. Let's disable that everywhere, for consistency.
|
|
188
|
+
this._errorCallback = cb;
|
|
221
189
|
|
|
190
|
+
// Some browsers (Firefox) call onerror on every host, while others
|
|
191
|
+
// (Chrome) do nothing. Let's disable that everywhere, for consistency.
|
|
222
192
|
this._worker.addEventListener("error", e => {
|
|
223
193
|
e.preventDefault();
|
|
224
194
|
e.stopPropagation();
|
|
225
195
|
});
|
|
226
196
|
}
|
|
227
|
-
|
|
228
197
|
_postMessage(obj, _hostID, transfer) {
|
|
229
198
|
// console.log('_postMessage', obj, _hostID, transfer);
|
|
230
199
|
if (this._workerType === "Worker") {
|
|
@@ -237,14 +206,12 @@ class PWBHost extends PWBBase {
|
|
|
237
206
|
throw new Error("WTF");
|
|
238
207
|
}
|
|
239
208
|
}
|
|
240
|
-
|
|
241
209
|
postMessage(userMessage, _hostID, transfer) {
|
|
242
210
|
// console.log('postMessage', userMessage, _hostID, transfer);
|
|
243
211
|
const actuallyPostMessage = (resolve, reject) => {
|
|
244
212
|
const messageID = messageIDs;
|
|
245
213
|
messageIDs += 1;
|
|
246
214
|
const messageToSend = [MSGTYPE_QUERY, messageID, userMessage, this._hostID];
|
|
247
|
-
|
|
248
215
|
this._callbacks.set(messageID, (error, result) => {
|
|
249
216
|
if (error) {
|
|
250
217
|
reject(error);
|
|
@@ -252,10 +219,8 @@ class PWBHost extends PWBBase {
|
|
|
252
219
|
resolve(result);
|
|
253
220
|
}
|
|
254
221
|
});
|
|
255
|
-
|
|
256
222
|
this._postMessage(messageToSend, undefined, transfer);
|
|
257
223
|
};
|
|
258
|
-
|
|
259
224
|
return new Promise((resolve, reject) => {
|
|
260
225
|
// Don't send a message until hostID is known, otherwise it's a race
|
|
261
226
|
// condition and sometimes hostID will be undefined.
|
|
@@ -268,25 +233,21 @@ class PWBHost extends PWBBase {
|
|
|
268
233
|
}
|
|
269
234
|
});
|
|
270
235
|
}
|
|
271
|
-
|
|
272
236
|
_onMessage(e) {
|
|
273
237
|
const common = this._onMessageCommon(e);
|
|
274
|
-
|
|
275
238
|
if (!common) {
|
|
276
239
|
return;
|
|
277
240
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
241
|
+
const {
|
|
242
|
+
message,
|
|
243
|
+
type
|
|
244
|
+
} = common;
|
|
282
245
|
if (type === MSGTYPE_HOST_ID) {
|
|
283
246
|
if (message[2] !== undefined && typeof message[2] !== "number") {
|
|
284
247
|
throw new Error("Invalid hostID");
|
|
285
248
|
}
|
|
286
|
-
|
|
287
249
|
const hostID = message[2];
|
|
288
250
|
this._hostID = hostID;
|
|
289
|
-
|
|
290
251
|
if (this._hostIDQueue !== undefined) {
|
|
291
252
|
this._hostIDQueue.forEach(func => {
|
|
292
253
|
// Not entirely sure why setTimeout is needed, might be just for unit tests
|
|
@@ -294,74 +255,68 @@ class PWBHost extends PWBBase {
|
|
|
294
255
|
func();
|
|
295
256
|
}, 0);
|
|
296
257
|
});
|
|
297
|
-
|
|
298
258
|
this._hostIDQueue = undefined; // Never needed again after initial setup
|
|
299
259
|
}
|
|
300
260
|
} else if (type === MSGTYPE_WORKER_ERROR) {
|
|
301
261
|
if (message[2] !== undefined && message[2] !== null && typeof message[2] === "object") {
|
|
302
262
|
const error = fromFakeError(message[2]);
|
|
303
|
-
|
|
304
263
|
if (this._errorCallback !== undefined) {
|
|
305
264
|
this._errorCallback(error);
|
|
306
265
|
}
|
|
307
266
|
}
|
|
308
267
|
}
|
|
309
268
|
}
|
|
310
|
-
|
|
311
269
|
}
|
|
312
|
-
|
|
313
270
|
class PWBWorker extends PWBBase {
|
|
314
271
|
constructor() {
|
|
315
|
-
super();
|
|
272
|
+
super();
|
|
316
273
|
|
|
274
|
+
// Only actually used for SharedWorker
|
|
317
275
|
this._hosts = new Map();
|
|
318
276
|
this._maxHostID = -1;
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
typeof SharedWorkerGlobalScope !== "undefined" &&
|
|
277
|
+
if (
|
|
278
|
+
// @ts-expect-error
|
|
279
|
+
typeof SharedWorkerGlobalScope !== "undefined" &&
|
|
280
|
+
// @ts-expect-error
|
|
322
281
|
self instanceof SharedWorkerGlobalScope) {
|
|
323
282
|
this._workerType = "SharedWorker";
|
|
324
283
|
self.addEventListener("connect", e => {
|
|
325
284
|
// @ts-expect-error
|
|
326
285
|
const port = e.ports[0];
|
|
327
|
-
port.addEventListener("message", e2 => this._onMessage(e2));
|
|
328
|
-
|
|
286
|
+
port.addEventListener("message", e2 => this._onMessage(e2));
|
|
329
287
|
port.start();
|
|
330
288
|
this._maxHostID += 1;
|
|
331
289
|
const hostID = this._maxHostID;
|
|
332
|
-
|
|
333
290
|
this._hosts.set(hostID, {
|
|
334
291
|
port
|
|
335
|
-
});
|
|
336
|
-
|
|
292
|
+
});
|
|
337
293
|
|
|
294
|
+
// Send back hostID to this host, otherwise it has no way to know it
|
|
338
295
|
this._postMessage([MSGTYPE_HOST_ID, -1, hostID], hostID);
|
|
339
296
|
});
|
|
340
297
|
self.addEventListener("error", e => {
|
|
341
|
-
logError(e.error);
|
|
298
|
+
logError(e.error);
|
|
342
299
|
|
|
300
|
+
// Just send to first host, so as to not duplicate error tracking
|
|
343
301
|
const hostID = this._hosts.keys().next().value;
|
|
344
|
-
|
|
345
302
|
if (hostID !== undefined) {
|
|
346
303
|
this._postMessage([MSGTYPE_WORKER_ERROR, -1, toFakeError(e.error)], hostID);
|
|
347
304
|
}
|
|
348
305
|
});
|
|
349
306
|
} else {
|
|
350
307
|
this._workerType = "Worker";
|
|
351
|
-
self.addEventListener("message", this._onMessage);
|
|
308
|
+
self.addEventListener("message", this._onMessage);
|
|
309
|
+
|
|
310
|
+
// Since this is not a Shared Worker, hostID is always 0 so it's not strictly required to
|
|
352
311
|
// send this back, but it makes the API a bit more consistent if there is the same
|
|
353
312
|
// initialization handshake in both cases.
|
|
354
|
-
|
|
355
313
|
this._postMessage([MSGTYPE_HOST_ID, -1, 0], 0);
|
|
356
|
-
|
|
357
314
|
self.addEventListener("error", e => {
|
|
358
315
|
logError(e.error);
|
|
359
|
-
|
|
360
316
|
this._postMessage([MSGTYPE_WORKER_ERROR, -1, toFakeError(e.error)]);
|
|
361
317
|
});
|
|
362
318
|
}
|
|
363
319
|
}
|
|
364
|
-
|
|
365
320
|
_postMessage(obj, targetHostID, transfer) {
|
|
366
321
|
// console.log('_postMessage', obj, targetHostID);
|
|
367
322
|
if (this._workerType === "SharedWorker") {
|
|
@@ -381,14 +336,12 @@ class PWBWorker extends PWBBase {
|
|
|
381
336
|
throw new Error("WTF");
|
|
382
337
|
}
|
|
383
338
|
}
|
|
384
|
-
|
|
385
339
|
postMessage(userMessage, targetHostID, transfer) {
|
|
386
340
|
// console.log('postMessage', userMessage, targetHostID);
|
|
387
341
|
const actuallyPostMessage = (resolve, reject) => {
|
|
388
342
|
const messageID = messageIDs;
|
|
389
343
|
messageIDs += 1;
|
|
390
344
|
const messageToSend = [MSGTYPE_QUERY, messageID, userMessage];
|
|
391
|
-
|
|
392
345
|
this._callbacks.set(messageID, (error, result) => {
|
|
393
346
|
if (error) {
|
|
394
347
|
reject(error);
|
|
@@ -396,36 +349,29 @@ class PWBWorker extends PWBBase {
|
|
|
396
349
|
resolve(result);
|
|
397
350
|
}
|
|
398
351
|
});
|
|
399
|
-
|
|
400
352
|
this._postMessage(messageToSend, targetHostID, transfer);
|
|
401
353
|
};
|
|
402
|
-
|
|
403
354
|
return new Promise((resolve, reject) => {
|
|
404
355
|
actuallyPostMessage(resolve, reject);
|
|
405
356
|
});
|
|
406
357
|
}
|
|
407
|
-
|
|
408
358
|
_onMessage(e) {
|
|
409
359
|
const common = this._onMessageCommon(e);
|
|
410
|
-
|
|
411
360
|
if (!common) {
|
|
412
361
|
return;
|
|
413
362
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
363
|
+
const {
|
|
364
|
+
message,
|
|
365
|
+
type
|
|
366
|
+
} = common;
|
|
418
367
|
if (type === MSGTYPE_HOST_CLOSE) {
|
|
419
368
|
if (typeof message[2] !== "number") {
|
|
420
369
|
throw new Error("Invalid hostID");
|
|
421
370
|
}
|
|
422
|
-
|
|
423
371
|
const hostID = message[2];
|
|
424
|
-
|
|
425
372
|
this._hosts.delete(hostID);
|
|
426
373
|
}
|
|
427
374
|
}
|
|
428
|
-
|
|
429
375
|
}
|
|
430
376
|
|
|
431
377
|
export { PWBHost, PWBWorker };
|