Skip to content

Commit 9942656

Browse files
committed
Clean up & annotate code. Fixes #8.
1 parent 8f51450 commit 9942656

File tree

2 files changed

+50
-21
lines changed

2 files changed

+50
-21
lines changed

greenlet.js

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,51 @@
11
/** Move an async function into its own thread.
2-
* @param {Function} fn The (async) function to run in a Worker.
2+
* @param {Function} asyncFunction An (async) function to run in a Worker.
33
*/
4-
export default function greenlet(fn) {
5-
let w = new Worker(URL.createObjectURL(new Blob([
6-
'onmessage=('+(
7-
f => ({ data }) => Promise.resolve().then(
8-
() => f.apply(f, data[1])
9-
).then(
10-
d => { postMessage([data[0], null, d]); },
11-
e => { postMessage([data[0], ''+e]); }
12-
)
13-
)+')('+fn+')'
14-
]))),
15-
c = 0,
16-
p = {};
17-
w.onmessage = ({ data: [c,e,d] }) => {
18-
p[c][e?1:0](e||d);
19-
delete p[c];
4+
export default function greenlet(asyncFunction) {
5+
// Create an "inline" worker
6+
let worker = new Worker(
7+
// The URL is a pointer to a stringified function (as a blob object)
8+
URL.createObjectURL(
9+
new Blob([
10+
// Register our wrapper function as the message handler
11+
'onmessage=('+(
12+
// f() is the user-supplied async function
13+
userFunc => ({ data }) => Promise.resolve().then(
14+
// invoking within then() captures exceptions in f() as rejections
15+
() => userFunc.apply(userFunc, data[1])
16+
).then(
17+
d => {
18+
// success handler - callback(id, null, result)
19+
postMessage([data[0], null, d]);
20+
},
21+
e => {
22+
// error handler - callback(id, err)
23+
postMessage([data[0], ''+e]);
24+
}
25+
)
26+
)+')('+asyncFunction+')' // pass user-supplied function to the closure
27+
])
28+
)
29+
),
30+
31+
// A simple counter is used to generate worker-global unique ID's for RPC:
32+
currentId = 0,
33+
34+
// Outward-facing promises store their "controllers" (`[request, reject]`) here:
35+
promises = {};
36+
37+
// Handle RPC results/errors coming back out of the worker
38+
worker.onmessage = ({ data: [id, err, result] }) => {
39+
// invoke the promise's resolve() or reject() depending on whether there was an error.
40+
promises[id][err ? 1 : 0](err || result);
41+
// ... then delete the promise controller
42+
delete promises[id];
2043
};
21-
return (...a) => new Promise( (y, n) => {
22-
p[++c] = [y, n];
23-
w.postMessage([c, a]);
44+
45+
// Return a proxy function that forwards calls to the worker & returns a promise for the result.
46+
return (...args) => new Promise( (resolve, reject) => {
47+
promises[++currentId] = [resolve, reject];
48+
// Send an RPC call to the worker - call(id, params)
49+
worker.postMessage([currentId, args]);
2450
});
2551
}

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
"release": "npm run -s prepare && npm test && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags && npm publish"
1212
},
1313
"eslintConfig": {
14-
"extends": "eslint-config-developit"
14+
"extends": "eslint-config-developit",
15+
"rules": {
16+
"prefer-spread": 0
17+
}
1518
},
1619
"files": [
1720
"greenlet.js",

0 commit comments

Comments
 (0)