- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我一直在探索 async_hooks
API 来跟踪异步事件的状态。我发现 destroy
回调并不总是为每个相应的 init
回调调用。
这是一个简单的重现:
const asyncHooks = require("async_hooks");
const fs = require("fs");
const https = require("https");
asyncHooks
.createHook({
init(asyncId, type, triggerId) {
fs.writeSync(1, `init ${asyncId} ${triggerId} ${type}\n`);
},
destroy(asyncId) {
fs.writeSync(1, `destroy ${asyncId}\n`);
},
promiseResolve(asyncId) {
fs.writeSync(1, `promiseResolve ${asyncId}\n`);
}
})
.enable();
https.get("https://www.google.com", res => {
console.log("status code - " + res.statusCode);
});
上面记录了发出简单 HTTP 请求时的所有 init
和 destroy
回调。
这是输出:
$ node bug.js
* init 5 1 TCPWRAP
* init 6 1 TLSWRAP
init 7 1 TickObject
* init 8 1 DNSCHANNEL
init 9 6 GETADDRINFOREQWRAP
init 10 1 TickObject
* init 11 10 HTTPPARSER
* init 12 10 HTTPPARSER
init 13 10 TickObject
init 14 5 TCPCONNECTWRAP
destroy 7
destroy 10
destroy 13
destroy 9
init 15 6 WRITEWRAP
destroy 14
status code - 200
init 16 12 TickObject
init 17 6 TickObject
init 18 6 TickObject
init 19 6 TickObject
init 20 6 TickObject
destroy 15
destroy 16
destroy 17
destroy 18
destroy 19
destroy 20
init 21 6 TickObject
init 22 6 TickObject
init 23 6 TickObject
init 24 6 TickObject
init 25 6 TickObject
init 26 6 TickObject
destroy 21
destroy 22
destroy 23
destroy 24
destroy 25
destroy 26
init 27 6 TickObject
init 28 6 TickObject
init 29 6 TickObject
destroy 27
destroy 28
destroy 29
init 30 6 TickObject
init 31 6 TickObject
init 32 6 TickObject
init 33 6 TickObject
init 34 6 TickObject
init 35 6 TickObject
init 36 6 TickObject
destroy 30
destroy 31
destroy 32
destroy 33
destroy 34
destroy 35
destroy 36
init 37 6 TickObject
init 38 6 TickObject
init 39 6 TickObject
destroy 37
destroy 38
destroy 39
init 40 6 TickObject
init 41 6 TickObject
destroy 40
destroy 41
init 42 6 TickObject
init 43 6 TickObject
init 44 6 TickObject
init 45 6 TickObject
destroy 42
destroy 43
destroy 44
destroy 45
我对上面的日志进行了注释,为每个没有相应 destroy
回调的 init
回调添加了星号 (*)。正如您所看到的,TCPWRAP
、TLSWRAP
、DNSCHANNEL
、HTTPPARSER
回调类型似乎是有问题的类型。
我担心这种不对称会导致使用这种方法进行“连续本地存储”的各个 Node 模块中的内存泄漏,例如https://github.com/Jeff-Lewis/cls-hooked
最佳答案
将异步跟踪集成到Data-Forge Notebook后,我有两条建议可以帮助解决这个问题。 .
首先,您应该将想要启用异步 Hook 的代码包装在其自己的父异步资源中。将此视为一个异步上下文,它将您想要跟踪的代码与您不想跟踪的代码分开。
通过这种方式,您可以将异步跟踪隔离到仅真正需要它的代码。如果您这样做,那么您将故意忽略您不关心的其他代码中的异步操作,并且很可能是那些导致问题的异步操作,因此这样做会将它们排除在考虑范围之外。
这里有一些伪代码来解释我的意思:
const async_hooks = require("async_hooks");
function initAsyncTracking(trackedAsyncId) {
const asyncHook = async_hooks.createHook({ // Initialise the async hooks API.
init: (asyncId, type, triggerAsyncId, resource) => {
// ... Add the async operation to your tracking if triggerAsyncId is equal to trackedAsyncId (the ID of our tracked parent async operation).
// ... You also need to track the operation if triggerAsyncId is a child async operation of trackedAsyncId (you need to store enough information in your record to make this check).
},
destroy: asyncId => {
// ... Remove the async operation if it was tracked ...
},
promiseResolve: asyncId => {
// ... Remove the async operation if it was tracked ...
},
});
asyncHook.enable(); // Enable tracking of async operations.
}
// ... code executed here (eg outside the async resource) isn't tracked.
const asyncTrackingResource = new async_hooks.AsyncResource("MY-ASYNC-RESOURCE"); // Create an async resource to be a parent of any async operations we want to track.
asyncTrackingResource.runInAsyncScope(() => {
const trackedAsyncId = async_hooks.executionAsyncId(); // Get the id of the async resource we created.
initAsyncTracking(trackedAsyncId );
// ... code executed here (eg inside the async resource) will be tracked.
});
// ... code executed here (eg outside the async resource) isn't tracked.
我的第二条建议与 DNSCHANNEL 异步资源有关。我发现这个异步资源是由 Node.js 运行时库延迟创建并存储在全局变量中的。我能够通过 Node.js request
模块触发它的创建。所以这是一个系统异步资源,由您的代码间接创建并全局缓存(可能是为了性能?)。
这有点 hacky,但我发现如果我在异步跟踪代码之外强制创建全局 DNSCHANNEL 资源,那么它就不再是问题了
以下是预创建 DNSCHANNEL 异步资源的代码:
const { Resolver } = require("dns");
const hackWorkaround = new Resolver();
这有点难看,但它强制在我的异步跟踪代码运行之前创建它,因此 Node.js 似乎从未清理过这个特定资源,这并不是问题。
也可能是 Node.js 具有其他全局异步资源(例如此资源),这可能会给您带来问题。如果您发现更多请告诉我!
关于node.js - 并非所有资源都调用 Node async_hooks destroy 生命周期事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54578654/
Failed to compile. ./node_modules/vm2/lib/resolver-compat.js Module not found: Can't resolve 'async_
我正在尝试使用 Node async_hooks 通过异步堆栈跟踪上下文。它适用于大多数情况,但是我发现这个用例我不知道如何解决: service.js: const asyncHooks = req
我一直在探索 async_hooks API 来跟踪异步事件的状态。我发现 destroy 回调并不总是为每个相应的 init 回调调用。 这是一个简单的重现: const asyncHooks =
我正在尝试从官方 Node api 文档运行 Async Hooks 的测试代码,但在控制台中收到错误 Error: Cannot find module 'async_hooks' 。我已经在脚本顶
Node 8 中有一个名为“async_hook”的新 API,我相信它应该使模块作者能够打印异步堆栈跟踪。我正在寻找类似于 chrome dev-tools 异步堆栈跟踪实现的东西,但在开发/调试期
所以我在 node.js 中构建了一个脚本,它应该接收 csv 文件,解析它们并将它们输入到数据库中。 有时,当我调试我的代码时,它会像 async_hooks.js 文件中的一个不可见断点一样停止,
async_hooks在 Node v8 中作为实验引入。因为名字类似于ES2017 async看起来它们可能在某种程度上相关。他们是吗?如果是,以什么方式(互补或竞争)? 最佳答案 async_ho
我是一名优秀的程序员,十分优秀!