/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
lib/internal/async_local_storage/async_hooks.js
168 строк
4 KB
Matteo Collina
timers: do not retain a reference to the async store after firing
19 июл 2026, 21:30
Не верифицирован
19 июл 2026, 21:30
d25cde4
Код
Авторство
О чём код?
'use strict'; const { ArrayPrototypeIndexOf, ArrayPrototypePush, ArrayPrototypeSplice, ObjectIs, ReflectApply, Symbol, } = primordials; const { validateObject, } = require('internal/validators'); const { symbols: { async_local_storage_context_symbol, }, } = require('internal/async_hooks'); const { AsyncResource, createHook, executionAsyncResource, } = require('async_hooks'); const RunScope = require('internal/async_local_storage/run_scope'); const { kEmptyObject } = require('internal/util'); const storageList = []; function getOrCreateResourceStore(resource) { return resource[async_local_storage_context_symbol] ??= { __proto__: null }; } const storageHook = createHook({ init(asyncId, type, triggerAsyncId, resource) { const currentResource = executionAsyncResource(); // Value of currentResource is always a non null object for (let i = 0; i < storageList.length; ++i) { storageList[i]._propagate(resource, currentResource, type); } }, }); class AsyncLocalStorage { #defaultValue = undefined; #name = undefined; /** * @typedef {object} AsyncLocalStorageOptions * @property {any} [defaultValue] - The default value to use when no value is set. * @property {string} [name] - The name of the storage. */ /** * @param {AsyncLocalStorageOptions} [options] */ constructor(options = kEmptyObject) { this.kResourceStore = Symbol('kResourceStore'); this.enabled = false; validateObject(options, 'options'); this.#defaultValue = options.defaultValue; if (options.name !== undefined) { this.#name = `${options.name}`; } this._enable(); } /** @type {string} */ get name() { return this.#name || ''; } static bind(fn) { return AsyncResource.bind(fn); } static snapshot() { return AsyncLocalStorage.bind((cb, ...args) => cb(...args)); } disable() { if (this.enabled) { this.enabled = false; // If this.enabled, the instance must be in storageList const index = ArrayPrototypeIndexOf(storageList, this); ArrayPrototypeSplice(storageList, index, 1); if (storageList.length === 0) { storageHook.disable(); } } } _enable() { if (!this.enabled) { this.enabled = true; ArrayPrototypePush(storageList, this); storageHook.enable(); } } // Propagate the context from a parent resource to a child one _propagate(resource, triggerResource, type) { const store = triggerResource[async_local_storage_context_symbol]?.[this.kResourceStore]; if (this.enabled) { const resourceStore = getOrCreateResourceStore(resource); resourceStore[this.kResourceStore] = store; } } enterWith(store) { this._enable(); const resource = executionAsyncResource(); const resourceStore = getOrCreateResourceStore(resource); resourceStore[this.kResourceStore] = store; } run(store, callback, ...args) { // Avoid creation of an AsyncResource if store is already active if (ObjectIs(store, this.getStore())) { return ReflectApply(callback, null, args); } this._enable(); const resource = executionAsyncResource(); const resourceStore = getOrCreateResourceStore(resource); const oldStore = resourceStore[this.kResourceStore]; resourceStore[this.kResourceStore] = store; try { return ReflectApply(callback, null, args); } finally { resourceStore[this.kResourceStore] = oldStore; } } exit(callback, ...args) { if (!this.enabled) { return ReflectApply(callback, null, args); } this.disable(); try { return ReflectApply(callback, null, args); } finally { this._enable(); } } getStore() { if (this.enabled) { const resource = executionAsyncResource(); const resourceStore = resource[async_local_storage_context_symbol]; if (resourceStore === undefined || !(this.kResourceStore in resourceStore)) { return this.#defaultValue; } return resourceStore[this.kResourceStore]; } return this.#defaultValue; } withScope(store) { return new RunScope(this, store); } } module.exports = AsyncLocalStorage;