async-hook-jl
Version:
Inspect the life of handle objects in node
134 lines (109 loc) • 3.19 kB
JavaScript
'use strict';
const asyncWrap = process.binding('async_wrap');
const TIMERWRAP = asyncWrap.Providers.TIMERWRAP;
const patchs = {
'nextTick': require('./patches/next-tick.js'),
'promise': require('./patches/promise.js'),
'timers': require('./patches/timers.js')
};
const ignoreUIDs = new Set();
function State() {
this.enabled = false;
this.counter = 0;
}
function Hooks() {
const initFns = this.initFns = [];
const preFns = this.preFns = [];
const postFns = this.postFns = [];
const destroyFns = this.destroyFns = [];
this.init = function (uid, provider, parentUid, parentHandle) {
// Ignore TIMERWRAP, since setTimeout etc. is monkey patched
if (provider === TIMERWRAP) {
ignoreUIDs.add(uid);
return;
}
// call hooks
for (const hook of initFns) {
hook(uid, this, provider, parentUid, parentHandle);
}
};
this.pre = function (uid) {
if (ignoreUIDs.has(uid)) return;
// call hooks
for (const hook of preFns) {
hook(uid, this);
}
};
this.post = function (uid, didThrow) {
if (ignoreUIDs.has(uid)) return;
// call hooks
for (const hook of postFns) {
hook(uid, this, didThrow);
}
};
this.destroy = function (uid) {
// Cleanup the ignore list if this uid should be ignored
if (ignoreUIDs.has(uid)) {
ignoreUIDs.delete(uid);
return;
}
// call hooks
for (const hook of destroyFns) {
hook(uid);
}
};
}
Hooks.prototype.add = function (hooks) {
if (hooks.init) this.initFns.push(hooks.init);
if (hooks.pre) this.preFns.push(hooks.pre);
if (hooks.post) this.postFns.push(hooks.post);
if (hooks.destroy) this.destroyFns.push(hooks.destroy);
};
function removeElement(array, item) {
const index = array.indexOf(item);
if (index === -1) return;
array.splice(index, 1);
}
Hooks.prototype.remove = function (hooks) {
if (hooks.init) removeElement(this.initFns, hooks.init);
if (hooks.pre) removeElement(this.preFns, hooks.pre);
if (hooks.post) removeElement(this.postFns, hooks.post);
if (hooks.destroy) removeElement(this.destroyFns, hooks.destroy);
};
function AsyncHook() {
this._state = new State();
this._hooks = new Hooks();
// expose version for conflict detection
this.version = require('./package.json').version;
// expose the Providers map
this.providers = asyncWrap.Providers;
// apply patches
for (const key of Object.keys(patchs)) {
patchs[key].call(this);
}
// setup async wrap
if (process.env.hasOwnProperty('NODE_ASYNC_HOOK_WARNING')) {
console.warn('warning: you are using async-hook-jl which is unstable.');
}
asyncWrap.setupHooks({
init: this._hooks.init,
pre: this._hooks.pre,
post: this._hooks.post,
destroy: this._hooks.destroy
});
}
module.exports = AsyncHook;
AsyncHook.prototype.addHooks = function (hooks) {
this._hooks.add(hooks);
};
AsyncHook.prototype.removeHooks = function (hooks) {
this._hooks.remove(hooks);
};
AsyncHook.prototype.enable = function () {
this._state.enabled = true;
asyncWrap.enable();
};
AsyncHook.prototype.disable = function () {
this._state.enabled = false;
asyncWrap.disable();
};