like-thread 1.0.2 → 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 +55 -21
- package/package.json +1 -1
- package/worker.js +14 -9
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) {
|
|
@@ -104,6 +110,34 @@ module.exports = class Thread {
|
|
|
104
110
|
})
|
|
105
111
|
|
|
106
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)
|
|
107
141
|
}
|
|
108
142
|
|
|
109
143
|
_onMessage (msg) {
|
|
@@ -113,12 +147,18 @@ module.exports = class Thread {
|
|
|
113
147
|
return
|
|
114
148
|
}
|
|
115
149
|
|
|
116
|
-
// console.log('_onMessage', msg, !!req.iterator ? 'iterator' : 'promise')
|
|
117
|
-
|
|
118
150
|
if (msg.error) {
|
|
119
151
|
this.requests.delete(msg.id)
|
|
120
152
|
|
|
121
|
-
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
|
+
}
|
|
122
162
|
|
|
123
163
|
if (req.resolver) {
|
|
124
164
|
req.resolver.reject(err)
|
|
@@ -158,11 +198,15 @@ module.exports = class Thread {
|
|
|
158
198
|
}
|
|
159
199
|
|
|
160
200
|
call (...args) {
|
|
201
|
+
if (this.closing) {
|
|
202
|
+
return Promise.reject(new Error('Thread is closed'))
|
|
203
|
+
}
|
|
204
|
+
|
|
161
205
|
if (this.id === 0xffffffff) {
|
|
162
|
-
this.id =
|
|
206
|
+
this.id = 0
|
|
163
207
|
}
|
|
164
208
|
|
|
165
|
-
const id = this.id
|
|
209
|
+
const id = ++this.id
|
|
166
210
|
|
|
167
211
|
const sab = new SharedArrayBuffer(4)
|
|
168
212
|
const control = new Int32Array(sab)
|
|
@@ -241,19 +285,15 @@ module.exports = class Thread {
|
|
|
241
285
|
return item
|
|
242
286
|
},
|
|
243
287
|
|
|
244
|
-
return
|
|
245
|
-
iterator.closed = true
|
|
246
|
-
|
|
288
|
+
async return () {
|
|
247
289
|
Atomics.store(control, 0, 2)
|
|
248
290
|
Atomics.notify(control, 0, 1)
|
|
249
291
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
// iterator.queue.length = 0
|
|
254
|
-
// iterator.resolver.resolve()
|
|
292
|
+
try {
|
|
293
|
+
await iterator.resolver.promise
|
|
294
|
+
} catch {}
|
|
255
295
|
|
|
256
|
-
return
|
|
296
|
+
return { done: true }
|
|
257
297
|
}
|
|
258
298
|
}
|
|
259
299
|
}
|
|
@@ -285,12 +325,6 @@ module.exports = class Thread {
|
|
|
285
325
|
finally (onFinally) {
|
|
286
326
|
return this.promise.finally(onFinally)
|
|
287
327
|
}
|
|
288
|
-
|
|
289
|
-
async close () {
|
|
290
|
-
this.worker.postMessage({ command: 'exit' })
|
|
291
|
-
|
|
292
|
-
await this.promise.catch(noop)
|
|
293
|
-
}
|
|
294
328
|
}
|
|
295
329
|
|
|
296
330
|
function noop () {}
|
package/package.json
CHANGED
package/worker.js
CHANGED
|
@@ -9,6 +9,11 @@ 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
19
|
process.exit()
|
|
@@ -16,21 +21,16 @@ parentPort.on('message', async (msg) => {
|
|
|
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
|
})
|