20分钟6个示例4个动图教你学会Async Hooks

序幕

async_hooks模块提供了一个全新的功能世界,但作为 Node.js 爱好者,我最感兴趣的是,它可以让您轻松了解我们在应用程序中经常执行的一些任务的幕后情况。

在本文中,我将尝试借助async_hooks模块来演示和解释一个典型的异步资源的生命周期。

Async Hooks API 简介

async_hooks模块提供了一个 API 来注册回调,跟踪在 Node.js 应用程序中创建的异步资源的生命周期

异步资源表示具有关联回调的对象。此回调可能会被调用多次,例如,事件'connection'in net.createServer(),或者只是一次,如 in fs.open()。也可以在调用回调之前关闭资源。AsyncHook没有明确区分这些不同的情况,而是将它们表示为作为资源的抽象概念。

async_hooks允许您跟踪节点应用程序中发生的任何(好吧,几乎所有)异步内容。与代码中任何回调和本机承诺的注册和调用相关的事件可以通过异步挂钩进行侦听。换句话说,此 API 允许您将侦听器附加到宏任务和微任务生命周期事件。

核心 Async Hooks API 可以用以下代码片段表示:

const async_hooks = require('async_hooks')
// 当前执行上下文的 ID 
const eid = async_hooks.executionAsyncId() 
// 负责触发回调的句柄的 ID 
// 当前执行范围调用
const tid = async_hooks.triggerAsyncId()
const asyncHook = async_hooks.createHook({ 
  // 在对象构造期间调用
  init: function (asyncId, type, triggerAsyncId, resource) { }, 
  // 在调用资源回调之前调用
  before: function (asyncId) { }, 
  // 调用就在资源的回调完成之后
  :function (asyncId) { }, 
  // 当 AsyncWrap 实例被销毁时调用
  destroy: function (asyncId) { }, 
  // 只为 promise 资源调用,当 `resolve` 
  // 函数通过时`Promise` 构造函数被调用
  promiseResolve: function (asyncId) { } 
})
// 开始监听异步事件
asyncHook.enable() 
// 停止监听新的异步事件
asyncHook.disable()

 Async Hooks API 中没有那么多函数,总的来说,它看起来很简单。

executionAsyncId()函数返回当前执行上下文的标识符。

triggerAsyncId()函数返回负责调用当前正在执行的回调的资源的 ID

异步资源的生命周期

异步资源是作为异步操作的一部分创建的。异步资源只不过是用于跟踪异步操作的对象。因此,它们很自然地与一个回调相关联,回调将在操作完成后执行。一旦异步资源达到其目的,它就可以像任何其他对象一样被垃圾回收。

一个非常简单的例子是setTimeoutsetTimeout函数返回为跟踪计时器而创建的异步资源 ( Timeout) 作为函数的返回值。setTimeout您可以通过调用Node REPL来查看它,如下所示:

 

该对象包含有用的信息,例如:

  • 其超时值 ( _idleTimeout)
  • 定时器回调 ( _onTimeout)
  • 无论是定时器还是间隔(_repeat
  • 超时是否有效 ( _destroyed)

这种异步资源的典型生命周期类似于

 “异步钩子”方便你的是通过提供“钩子”来监视上述生命周期的不同阶段的能力,我们可以附加回调函数。有四种常见类型的钩子,如initbefore和。它们在异步资源生命周期的以下四个阶段被触发。after  destroy

 

根据异步资源是否持久化(我稍后会谈到),异步资源的回调可能会执行 0 到多次。因此可以预料,对于某些异步资源, beforeand afterhooks可能会被多次调用,也可能根本不会被调用。例如 with setTimeoutbefore并且每个最多after只会触发一次,然后是 an ,而 with ,可以有多个and调用,然后是一个。initsetIntervalbeforeafterinit

例如,同时setTimeout创建setInterval异步Timeout资源。但是Timeout创建的资源setInterval是持久化Timeout资源,可以通过非空__repeat属性来标识。

Promiseobjects 略有不同,它们有一个额外的 hook promiseResolve,在 promise 被 resolved 或 rejected 后立即触发。

实际应用中的异步资源

在现实生活中的应用程序中,一个异步资源可能会在其生命周期内触发大量异步资源。考虑到上述讨论的细节,让我们看一下以下 HTTP 请求处理程序的假设示例。

 

这个 HTTP 请求处理程序的目的是

  • 通过 HTTP 接收一些数据
  • 将其存储在数据库中
  • 通过 HTTP 通知上游服务
  • 写一条日志消息到stdout

假设以上四个操作只创建了四个异步资源,让我们尝试将这四个资源的时间线绘制成如下图表(时间线的长度未按比例绘制)。请花几分钟时间阅读图表,并尝试将资源的时间线与我们讨论的异步资源生命周期相关联。

 设置定时器

首先,让我们看一个最简单的例子。在此示例中,我创建了一个超时为 1000 毫秒的计时器,并使用函数将“计时器回调”文本写入日志文件logger.write

当我运行上面的代码以及我设置的异步挂钩时,我将在我的log文件中看到以下输出。

根据这个输出,

  • 异步资源在被调用Timeout时被初始化。setTimeout
  • 超时到期后1000msbefore在执行计时器回调之前调用异步挂钩。
  • 执行计时器回调并"timer callback"记录文本。
  • 定时器回调执行后,after异步挂钩被调用。
  • Timeout资源被销毁并destroy调用了挂钩。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

脚本大神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值