Created
October 6, 2020 20:20
-
-
Save nicolo-ribaudo/eb0f798c89ba14e38093d6f1f93d0162 to your computer and use it in GitHub Desktop.
Synchronize async functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
const synchronize = require("./synchronize.cjs"); | |
synchronize.export({ | |
async getMyObj(value) { | |
await new Promise((resolve) => setTimeout(resolve, 2000)); | |
return { foo: value * 3 }; | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
const synchronize = require("./synchronize.cjs"); | |
const { | |
getMyObj, | |
[synchronize.unref]: unref | |
} = synchronize.import(__dirname + "/function.cjs"); | |
console.log("Start:", new Date()); | |
console.log("Result:", getMyObj(32)); | |
console.log("End:", new Date()); | |
unref(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { Worker, MessageChannel, parentPort, receiveMessageOnPort } = require("worker_threads"); | |
// IN WORKER | |
exports.export = function (functions) { | |
parentPort.once("message", port => { | |
port.on("message", async ({ lock, name, args }) => { | |
let message; | |
try { | |
message = { result: await functions[name](...args) }; | |
} catch (error) { | |
message = { error }; | |
} | |
port.postMessage(message); | |
Atomics.add(lock, 0, 1); | |
Atomics.notify(lock, 0); | |
}); | |
}); | |
}; | |
// IN CONSUMER | |
const unref = exports.unref = Symbol("unref"); | |
exports.import = function (filename) { | |
const worker = new Worker(filename); | |
const { port1, port2 } = new MessageChannel(); | |
worker.postMessage(port1, [port1]); | |
const cache = new Map(); | |
function initalizeFn(name) { | |
cache.set(name, fn); | |
return fn; | |
function fn(...args) { | |
const lock = new Int32Array(new SharedArrayBuffer(4)); | |
lock[0] = 0; | |
port2.postMessage({ lock, name, args }); | |
Atomics.wait(lock, 0, 0); | |
const message = receiveMessageOnPort(port2)?.message; | |
if (message && "result" in message) { | |
return message.result; | |
} else { | |
throw new Error(message?.error ?? "Unknown error"); | |
} | |
}; | |
} | |
return new Proxy({}, { | |
get(_, name) { | |
if (name === unref) return () => worker.unref(); | |
if (cache.has(name)) return cache.get(name); | |
return initalizeFn(name); | |
} | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment