AsyncResource

AsyncResource 类旨在通过嵌入器的异步资源进行扩展。 使用它,用户可以轻松触发自己资源的生命周期事件。

init 钩子将在实例化 AsyncResource 时触发。

以下是 AsyncResource API 的概述。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { AsyncResource, executionAsyncId } from 'node:async_hooks';

// AsyncResource() is meant to be extended. Instantiating a
// new AsyncResource() also triggers init. If triggerAsyncId is omitted then
// async_hook.executionAsyncId() is used.
const asyncResource = new AsyncResource(
type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false },
);

// Run a function in the execution context of the resource. This will
// * establish the context of the resource
// * trigger the AsyncHooks before callbacks
// * call the provided function `fn` with the supplied arguments
// * trigger the AsyncHooks after callbacks
// * restore the original execution context
asyncResource.runInAsyncScope(fn, thisArg, ...args);

// Call AsyncHooks destroy callbacks.
asyncResource.emitDestroy();

// Return the unique ID assigned to the AsyncResource instance.
asyncResource.asyncId();

// Return the trigger ID for the AsyncResource instance.
asyncResource.triggerAsyncId();

new AsyncResource(type[, options])

  • type string : 异步事件类型
  • options Object :
    • triggerAsyncId number : 创建此异步事件的执行上下文的 ID。 默认值: executionAsyncId()
    • requireManualDestroy boolean : 是否需要手动调用 emitDestroy() 来启动垃圾回收机制,默认值: false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class DBQuery extends AsyncResource {
constructor(db) {
super('DBQuery');
this.db = db;
}

getInfo(query, callback) {
this.db.get(query, (err, data) => {
this.runInAsyncScope(callback, null, err, data);
});
}

close() {
this.db = null;
this.emitDestroy();
}
}

结合async_hooks 实现一个类似线程局部存储的例子(该例子可用asyncLocalStorage 更简洁的实现):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const http = require('http');
const { AsyncResource, createHook, executionAsyncId } = require('async_hooks');

const authProfiles = {};
const hook = createHook({
init(asyncId, type, triggerAsyncId, resource) {
if (type === 'HTTP_PARSER') {
if (typeof authProfiles[asyncId] === 'undefined') {
authProfiles[asyncId] = {};
}
}
},
destroy(asyncId) {
authProfiles[asyncId] = null;
}
})
hook.enable();

http.createServer((req, res) => {
const asyncResource = new AsyncResource('HTTP_PARSER');
asyncResource.runInAsyncScope((req, res) => {
const asyncId = executionAsyncId();
authProfiles[asyncId].key = Date.now();
// 其它异步操作....
res.end();
}, null, req, res);
}).listen(3000);

静态方法

AsyncResource.bind(fn[, type[, thisArg]])

  • fn :绑定到当前执行上下文的函数。
  • type string :与底层 AsyncResource 关联的可选名称。
  • thisArg :绑定到当前执行上下文的函数的this指向

将给定函数绑定到当前执行上下文。

返回的函数将具有 asyncResource 属性,该属性引用函数绑定到的 AsyncResource

实例方法

asyncResource.bind(fn[, thisArg])

  • fn :绑定到当前AsyncResource 的函数。
  • thisArg :绑定到当前执行上下文的函数中this指向

将给定函数绑定到此AsyncResource 异步资源的执行上下文。

返回的函数将具有 asyncResource 属性,该属性引用函数绑定到的 AsyncResource

asyncResource.runInAsyncScope(fn[, thisArg, …args])

  • fn :在此异步资源的执行上下文中调用的函数。
  • thisArg :fn 中this的指向
  • ...args :传递给fn的参数

asyncResource.emitDestroy()

  • 返回asyncResource 的引用。

调用所有的 destroy 钩子。 这应该只被调用一次。 如果多次调用,则会报错。 此 必须 被手动调用。 如果资源留给 GC 收集,则永远不会调用 destroy 钩子。

asyncResource.asyncId()

  • 返回分配给资源的唯一 asyncId

asyncResource.triggerAsyncId()

  • 返回 传给 AsyncResource 构造函数的同一个 triggerAsyncId