Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

async_hooks 异步钩子

基础

源代码:lib/async_hooks.js

作用:用于追踪异步调用的触发顺序

用法

  • 引入

    • es6
      import async_hooks from 'async_hooks';
      
    • commonjs
      const async_hooks  = require('async_hooks')
      
  • 创建异步钩子并启用

    • 语法
    const hook = async_hooks.createHook({
        init(asyncId, type, triggerAsyncId, resource){
            const eid = executionAsyncId();
        fs.writeSync(
          1,
          `${type}(${asyncId}): trigger: ${triggerAsyncId} execution: ${eid}\n`);
        },
        before(asyncId){},
        after(asyncId){},
        destroy(asyncId){},
        promiseResolve(asyncId){}
    }).enable()
    
    • 三个概念

      • async scope:异步函数具有的上下文
      • asyncId:上下文在全局中独一无二的id记号(无论反复执行多少遍异步函数,这个id都不变),最外层的 asyncId 是 1
      • triggerAsyncId:当前异步函数是被哪个上下文异步调用的
    • 通过追踪asyncId和triggerAsyncId,就能得到异步调用的触发顺序

    • 可选五个钩子函数作为创建参数

      • 1、init在异步初始化时 触发
      • 2、关于回调函数
        • before在 回调将要执行前 触发
        • after在 回调执行完 触发
        • 对于promise异步,二者只会在.then或.catch等链式调用中触发,所以后面谈到的显式resolve里不会触发
      • 3、destory在异步资源销毁时触发(如果存在内存泄漏,依赖垃圾回收,则不会触发)
      • 4、promiseResolve在Promise中resovle执行时触发
        • resolve有两种执行方式
          • 显式:在resolve(结果)
          • 隐式:在.then(回调)
    • 记得.enable()启用

    • 注意:由于打印日志的 console.log 函数也是一个异步调用,如果我们在 钩子函数 中再调用 console.log 那么将再次触发相应的 hook 事件,造成死循环调用,所以要替换成同步打印方式,比如上面用的fs.writeSync(1,xxx)

      • 【问】为什么是1
      • 【答】在Linux中,一切设备都看作文件。每打开一个文件,就有一个文件描述符。程序启动时默认打开三个I/O设备文件:标准输入文件stdin,标准输出文件stdout,标准错误输出文件stderr,分别得到文件描述符 0, 1, 2
  • 启用后的使用

    • 语法
      • 返回 当前所处异步的asyncId
        async_hooks.executionAsyncId()
        
      • 返回 当前所处异步的triggerAsyncId
        async_hooks.triggerAsyncId()