node(14.2) 官网API
进阶API
进阶模块主要包括 性能分析模块和实验模块
assert
assert 模块提供了一组断言函数,用于验证不变量。
-
断言
断言是对程序某些假设的检查,用来精确捕获程序逻辑的错误,能够做一些类似预处理的事情
-
断言与异常
断言注重程序逻辑的错误,异常注重语法,环境等不可控因素导致的错误
断言以及单元测试库
断言经常被应用在单元测试中,下面列举常用的node断言和测试框架
-
断言库
-
单元测试框架
async_hooks / domain
async_hooks 和 domain 提供了对异步资源追踪和处理的能力,domain模块已被官方废弃,async_hooks作为domian的补充,但当前仍是实验性模块
-
异常和监控
try...catch...
可以捕获大部分的异常,但不能捕获异步错误,所以对于异步错误的处理更多是通过监听异常事件process.on('uncaughtException', function (err) {});
来完成,这导致node的异常处理和监控变得很棘手,所以相继推出了 domain 和 async_hooks 来完成对node异步的监控 -
async_hooks 生成traceId
async_hooks 对每一个函数(不论异步还是同步)提供了一个 async scope,我们可以通过调用 async_hooks.executionAsyncId() 来获取函数当前的 async scope 的 id(称为 asyncId),通过调用 async_hooks.triggerAsyncId() 来获取当前函数调用者的 asyncId(即triggerAsyncId)。
async_hooks.createHook 可以注册 4 个方法来跟踪所有异步资源的初始化(init)、回调之前(before)、回调之后(after)、销毁后(destroy)事件,并通过调用 .enable() 启用,调用 .disable() 关闭。
异步资源在创建时触发 init 事件函数,init 函数中的第 1 个参数代表该异步资源的 asyncId,type 表示异步资源的类型(例如 TCPWRAP、PROMISE、Timeout、Immediate、TickObject 等等),triggerAsyncId 表示该异步资源的调用者的 asyncId。异步资源在销毁时触发 destroy 事件函数,该函数只接收一个参数,即该异步资源的 asyncId。
在以上特性的支持下,就可以根据triggerAsyncId和asyncId的关系定位到函数之间的调用链关系,随即可以生成traceId完成链路调用的日志记录,以下是构造全链路traceId的代码
'use strict' const asyncHooks = require('async_hooks'); const fs = require('fs') const uuid = require('uuid').v4 const writStream = fs.createWriteStream('trace.log') // 存储上下文 const logCtxs = new Map() // 通过asyncHooks的init 和 destroy 维护和追踪上下文关系 asyncHooks.createHook({ init, destroy }).enable(); // 维护异步调用关系 function init(asyncId, type, triggerAsyncId) { const ctx = getCtx(triggerAsyncId) if (ctx) { logCtxs.set(asyncId, ctx) } else { logCtxs.set(asyncId, triggerAsyncId) } } // 删除失效对象 function destroy(asyncId) { logCtxs.delete(asyncId) } function getCtx(tid) { if (!tid) { return } if (typeof tid === 'object') { return tid } return getCtx(logCtxs.get(tid)) } function log(args){ const [trigger, asyncId] = [asyncHooks.triggerAsyncId(), asyncHooks.executionAsyncId()] const ctx = getCtx(asyncId) fs.writeSync(1, `{asyncId: ${ asyncId}, trigger: ${ trigger}, ctx: ${ JSON.stringify(ctx)} }: ${ args}\n\n`) } exports.log = log exports.logger = function logger() { return async (ctx, next) => { let reqContent = { main:ctx, traceId