like-thread 1.0.1 → 1.0.3
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/index.js +59 -23
- package/package.json +1 -1
- package/worker.js +15 -10
package/index.js
CHANGED
|
@@ -53,10 +53,12 @@ module.exports = class Thread {
|
|
|
53
53
|
this.isGenerator = !!entrypoint[2]
|
|
54
54
|
|
|
55
55
|
this.worker = new Worker(WORKER_SCRIPT, { eval: true, workerData, argv: opts.argv || null })
|
|
56
|
+
this._online = promiseWithResolvers()
|
|
56
57
|
|
|
57
|
-
this.id =
|
|
58
|
+
this.id = 0
|
|
58
59
|
this.requests = new Map()
|
|
59
60
|
|
|
61
|
+
this.worker.on('online', this._onOnline.bind(this))
|
|
60
62
|
this.worker.on('message', this._onMessage.bind(this))
|
|
61
63
|
|
|
62
64
|
this.promise = new Promise((resolve, reject) => {
|
|
@@ -75,6 +77,8 @@ module.exports = class Thread {
|
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
|
|
80
|
+
this._online.resolve(false)
|
|
81
|
+
|
|
78
82
|
reject(err)
|
|
79
83
|
})
|
|
80
84
|
|
|
@@ -93,6 +97,8 @@ module.exports = class Thread {
|
|
|
93
97
|
}
|
|
94
98
|
}
|
|
95
99
|
|
|
100
|
+
this._online.resolve(false)
|
|
101
|
+
|
|
96
102
|
const success = exitCode === 0 || exitCode === 130 || signal === 'SIGINT' || signal === 'SIGTERM' || signal === 'SIGHUP'
|
|
97
103
|
|
|
98
104
|
if (success) {
|
|
@@ -102,6 +108,36 @@ module.exports = class Thread {
|
|
|
102
108
|
}
|
|
103
109
|
})
|
|
104
110
|
})
|
|
111
|
+
|
|
112
|
+
this.promise.catch(noop)
|
|
113
|
+
|
|
114
|
+
this.closing = null
|
|
115
|
+
|
|
116
|
+
this.opened = false
|
|
117
|
+
this.opening = this.ready()
|
|
118
|
+
this.opening.then(() => {
|
|
119
|
+
this.opened = true
|
|
120
|
+
}).catch(noop)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async ready () {
|
|
124
|
+
if (this.opening) return this.opening
|
|
125
|
+
|
|
126
|
+
await this._online.promise
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async close () {
|
|
130
|
+
if (this.closing) return this.closing
|
|
131
|
+
|
|
132
|
+
this.closing = Promise.resolve()
|
|
133
|
+
|
|
134
|
+
this.worker.postMessage({ command: 'exit' })
|
|
135
|
+
|
|
136
|
+
await this.promise.catch(noop)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
_onOnline () {
|
|
140
|
+
this._online.resolve(true)
|
|
105
141
|
}
|
|
106
142
|
|
|
107
143
|
_onMessage (msg) {
|
|
@@ -111,12 +147,18 @@ module.exports = class Thread {
|
|
|
111
147
|
return
|
|
112
148
|
}
|
|
113
149
|
|
|
114
|
-
// console.log('_onMessage', msg, !!req.iterator ? 'iterator' : 'promise')
|
|
115
|
-
|
|
116
150
|
if (msg.error) {
|
|
117
151
|
this.requests.delete(msg.id)
|
|
118
152
|
|
|
119
|
-
const err = new Error(msg.error)
|
|
153
|
+
const err = new Error(msg.error.message)
|
|
154
|
+
|
|
155
|
+
if (msg.error.name) {
|
|
156
|
+
err.name = msg.error.name
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (typeof msg.error.code !== 'undefined') {
|
|
160
|
+
err.code = msg.error.code
|
|
161
|
+
}
|
|
120
162
|
|
|
121
163
|
if (req.resolver) {
|
|
122
164
|
req.resolver.reject(err)
|
|
@@ -156,11 +198,15 @@ module.exports = class Thread {
|
|
|
156
198
|
}
|
|
157
199
|
|
|
158
200
|
call (...args) {
|
|
201
|
+
if (this.closing) {
|
|
202
|
+
return Promise.reject(new Error('Thread is closed'))
|
|
203
|
+
}
|
|
204
|
+
|
|
159
205
|
if (this.id === 0xffffffff) {
|
|
160
|
-
this.id =
|
|
206
|
+
this.id = 0
|
|
161
207
|
}
|
|
162
208
|
|
|
163
|
-
const id = this.id
|
|
209
|
+
const id = ++this.id
|
|
164
210
|
|
|
165
211
|
const sab = new SharedArrayBuffer(4)
|
|
166
212
|
const control = new Int32Array(sab)
|
|
@@ -239,19 +285,15 @@ module.exports = class Thread {
|
|
|
239
285
|
return item
|
|
240
286
|
},
|
|
241
287
|
|
|
242
|
-
return
|
|
243
|
-
iterator.closed = true
|
|
244
|
-
|
|
288
|
+
async return () {
|
|
245
289
|
Atomics.store(control, 0, 2)
|
|
246
290
|
Atomics.notify(control, 0, 1)
|
|
247
291
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
// iterator.queue.length = 0
|
|
252
|
-
// iterator.resolver.resolve()
|
|
292
|
+
try {
|
|
293
|
+
await iterator.resolver.promise
|
|
294
|
+
} catch {}
|
|
253
295
|
|
|
254
|
-
return
|
|
296
|
+
return { done: true }
|
|
255
297
|
}
|
|
256
298
|
}
|
|
257
299
|
}
|
|
@@ -283,12 +325,6 @@ module.exports = class Thread {
|
|
|
283
325
|
finally (onFinally) {
|
|
284
326
|
return this.promise.finally(onFinally)
|
|
285
327
|
}
|
|
286
|
-
|
|
287
|
-
async close () {
|
|
288
|
-
this.worker.postMessage({ command: 'exit' })
|
|
289
|
-
|
|
290
|
-
await this.promise
|
|
291
|
-
|
|
292
|
-
// await this.worker.terminate()
|
|
293
|
-
}
|
|
294
328
|
}
|
|
329
|
+
|
|
330
|
+
function noop () {}
|
package/package.json
CHANGED
package/worker.js
CHANGED
|
@@ -9,28 +9,28 @@ const functionArgs = entrypoint[4] || ''
|
|
|
9
9
|
|
|
10
10
|
const fn = workerData.fn.replace(entrypoint[0], (isAsync ? 'async ' : '') + 'function ' + (isGenerator ? '* ' : '') + functionName + ' (' + (functionArgs) + ')')
|
|
11
11
|
|
|
12
|
+
// TODO: We can avoid re-creating the func inside the func by using prototypes
|
|
13
|
+
const source = fn + '\n\nreturn ' + functionName + '(...args)'
|
|
14
|
+
|
|
15
|
+
const wrap = new Function('require', '__dirname', '__filename', 'module', 'exports', 'parentPort', 'args', source) // eslint-disable-line no-new-func
|
|
16
|
+
|
|
12
17
|
parentPort.on('message', async (msg) => {
|
|
13
18
|
if (msg.command === 'exit') {
|
|
14
|
-
process.exit(
|
|
19
|
+
process.exit()
|
|
15
20
|
return
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
try {
|
|
19
|
-
// TODO: Optimize by creating the function only once by fixing the args
|
|
20
|
-
const source = fn + '\n\nmodule.exports = ' + functionName + '(...' + JSON.stringify(msg.args || []) + ')'
|
|
21
|
-
|
|
22
|
-
const wrap = new Function('require', '__dirname', '__filename', 'module', 'exports', 'parentPort', source) // eslint-disable-line no-new-func
|
|
23
|
-
|
|
24
24
|
const mod = { exports: {} }
|
|
25
25
|
|
|
26
|
-
wrap(require, __dirname, __filename, mod, mod.exports, parentPort)
|
|
27
|
-
|
|
28
|
-
const out = mod.exports
|
|
26
|
+
const out = wrap(require, __dirname, __filename, mod, mod.exports, parentPort, msg.args || [])
|
|
29
27
|
|
|
30
28
|
if (isGenerator) {
|
|
31
29
|
const control = new Int32Array(msg.sab)
|
|
32
30
|
const it = out[Symbol.asyncIterator] ? out[Symbol.asyncIterator]() : out[Symbol.iterator]()
|
|
33
31
|
|
|
32
|
+
let end = false
|
|
33
|
+
|
|
34
34
|
while (true) {
|
|
35
35
|
while (Atomics.load(control, 0) === 0) {
|
|
36
36
|
const res = Atomics.waitAsync(control, 0, 0)
|
|
@@ -51,6 +51,7 @@ parentPort.on('message', async (msg) => {
|
|
|
51
51
|
Atomics.store(control, 0, 0)
|
|
52
52
|
|
|
53
53
|
if (done) {
|
|
54
|
+
end = true
|
|
54
55
|
parentPort.postMessage({ id: msg.id, done: true })
|
|
55
56
|
break
|
|
56
57
|
}
|
|
@@ -59,6 +60,10 @@ parentPort.on('message', async (msg) => {
|
|
|
59
60
|
parentPort.postMessage({ id: msg.id, value, v: true })
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
if (!end) {
|
|
64
|
+
parentPort.postMessage({ id: msg.id, done: true })
|
|
65
|
+
}
|
|
66
|
+
|
|
62
67
|
return
|
|
63
68
|
}
|
|
64
69
|
|
|
@@ -72,6 +77,6 @@ parentPort.on('message', async (msg) => {
|
|
|
72
77
|
|
|
73
78
|
parentPort.postMessage({ id: msg.id, value: out, v: true })
|
|
74
79
|
} catch (err) {
|
|
75
|
-
parentPort.postMessage({ id: msg.id, error: err })
|
|
80
|
+
parentPort.postMessage({ id: msg.id, error: { name: err.name, code: err.code, message: err.message } })
|
|
76
81
|
}
|
|
77
82
|
})
|