nstdlib-nightly
Version:
Node.js standard library converted to runtime-agnostic ES modules.
116 lines (97 loc) • 3.14 kB
JavaScript
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/internal/promise_hooks.js
import { setPromiseHooks } from "nstdlib/stub/binding/async_wrap";
import { triggerUncaughtException } from "nstdlib/stub/binding/errors";
import { kEmptyObject } from "nstdlib/lib/internal/util";
import { validatePlainFunction } from "nstdlib/lib/internal/validators";
const hooks = {
init: [],
before: [],
after: [],
settled: [],
};
function initAll(promise, parent) {
const hookSet = Array.prototype.slice.call(hooks.init);
const exceptions = [];
for (let i = 0; i < hookSet.length; i++) {
const init = hookSet[i];
try {
init(promise, parent);
} catch (err) {
Array.prototype.push.call(exceptions, err);
}
}
// Triggering exceptions is deferred to allow other hooks to complete
for (let i = 0; i < exceptions.length; i++) {
const err = exceptions[i];
triggerUncaughtException(err, false);
}
}
function makeRunHook(list) {
return (promise) => {
const hookSet = Array.prototype.slice.call(list);
const exceptions = [];
for (let i = 0; i < hookSet.length; i++) {
const hook = hookSet[i];
try {
hook(promise);
} catch (err) {
Array.prototype.push.call(exceptions, err);
}
}
// Triggering exceptions is deferred to allow other hooks to complete
for (let i = 0; i < exceptions.length; i++) {
const err = exceptions[i];
triggerUncaughtException(err, false);
}
};
}
const beforeAll = makeRunHook(hooks.before);
const afterAll = makeRunHook(hooks.after);
const settledAll = makeRunHook(hooks.settled);
function maybeFastPath(list, runAll) {
return list.length > 1 ? runAll : list[0];
}
function update() {
const init = maybeFastPath(hooks.init, initAll);
const before = maybeFastPath(hooks.before, beforeAll);
const after = maybeFastPath(hooks.after, afterAll);
const settled = maybeFastPath(hooks.settled, settledAll);
setPromiseHooks(init, before, after, settled);
}
function stop(list, hook) {
const index = Array.prototype.indexOf.call(list, hook);
if (index >= 0) {
Array.prototype.splice.call(list, index, 1);
update();
}
}
function makeUseHook(name) {
const list = hooks[name];
return (hook) => {
validatePlainFunction(hook, `${name}Hook`);
Array.prototype.push.call(list, hook);
update();
return Function.prototype.bind.call(stop, null, list, hook);
};
}
const onInit = makeUseHook("init");
const onBefore = makeUseHook("before");
const onAfter = makeUseHook("after");
const onSettled = makeUseHook("settled");
function createHook({ init, before, after, settled } = kEmptyObject) {
const hooks = [];
if (init) Array.prototype.push.call(hooks, onInit(init));
if (before) Array.prototype.push.call(hooks, onBefore(before));
if (after) Array.prototype.push.call(hooks, onAfter(after));
if (settled) Array.prototype.push.call(hooks, onSettled(settled));
return () => {
for (const stop of hooks) {
stop();
}
};
}
export { createHook };
export { onInit };
export { onBefore };
export { onAfter };
export { onSettled };