Skip to content

Instantly share code, notes, and snippets.

@nicolo-ribaudo
Created October 6, 2020 20:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nicolo-ribaudo/eb0f798c89ba14e38093d6f1f93d0162 to your computer and use it in GitHub Desktop.
Save nicolo-ribaudo/eb0f798c89ba14e38093d6f1f93d0162 to your computer and use it in GitHub Desktop.
Synchronize async functions
"use strict";
const synchronize = require("./synchronize.cjs");
synchronize.export({
async getMyObj(value) {
await new Promise((resolve) => setTimeout(resolve, 2000));
return { foo: value * 3 };
}
});
"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();
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