当前位置: 首页 > news >正文

Node.js 中常用的异步函数讲解、如何检测异步操作时间和事件

✅ 1. process.nextTick()

功能:

process.nextTick() 用于将一个回调函数添加到当前阶段执行完后事件循环的下一轮开始前执行的队列中。

特点:

  • 优先级高于所有微任务(包括 Promise.then

  • 属于 Node.js 独有,不适用于浏览器

示例代码:

console.log('start');process.nextTick(() => {console.log('nextTick');
});Promise.resolve().then(() => {console.log('promise');
});console.log('end');

输出:

start
end
nextTick
promise

✅ 2. Promise.resolve().then(...)

功能:

Promise.then() 是 JavaScript 中的微任务机制之一,在本轮事件循环的所有同步代码执行完毕后立即执行

示例代码:

console.log('start');Promise.resolve().then(() => {console.log('promise');
});console.log('end');

输出:

start
end
promise

✅ 3. setTimeout(fn, delay)

功能:

将回调函数放入宏任务队列,在最少等待 delay 毫秒后执行(并不是精准时间,受事件循环调度影响)。

示例代码:

console.log('start');setTimeout(() => {console.log('timeout');
}, 0);console.log('end');

输出:

start
end
timeout

✅ 4. setInterval(fn, delay)

功能:

每隔 delay 毫秒重复执行一次函数。

特点:

  • 需要与 clearInterval() 搭配使用,防止无限循环或内存泄漏

示例代码:

let count = 0;
const timer = setInterval(() => {console.log('interval', count++);if (count > 2) clearInterval(timer);
}, 1000);

输出(每秒打印一次):

interval 0
interval 1
interval 2

✅ 5. clearTimeout(timeoutID)

功能:

取消之前由 setTimeout() 注册的定时器。

示例代码:

const timer = setTimeout(() => {console.log('should not run');
}, 1000);clearTimeout(timer);

输出:

不会有任何输出,因为定时器被取消了。


✅ 6. clearInterval(intervalID)

功能:

取消由 setInterval() 注册的循环任务。

示例代码:

let count = 0;
const id = setInterval(() => {console.log('interval', count++);if (count === 3) clearInterval(id);
}, 500);

🧠 拓展:其他常用异步任务

setImmediate(callback)

  • Node.js 独有。

  • 当前事件循环结束后立即执行,优先级比 setTimeout(..., 0) 更高。

setImmediate(() => console.log('setImmediate'));
setTimeout(() => console.log('setTimeout'), 0);

输出顺序视 Node 版本而定,setImmediate 通常优先。


🔁 执行优先级总结(Node.js):

同步代码 > process.nextTick > Promise.then > setTimeout/setInterval/setImmediate

✅ 实战演示对比:

console.log('start');process.nextTick(() => console.log('nextTick'));
Promise.resolve().then(() => console.log('promise'));
setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));console.log('end');

常见输出(Node.js v16+):

start
end
nextTick
promise
timeout
immediate

二、NodeJS如何监测异步操作的事件

在 Node.js 中,“异步操作”涉及到很多事件的注册与触发,而 监测异步操作的事件流转过程 对调试、排查内存泄漏、分析性能瓶颈等非常重要。Node.js 提供了多种方式可以 监测异步操作的生命周期与事件行为


🧩 1. 使用 async_hooks 模块(核心方案)

Node.js 从 v8.1.0 开始提供了 async_hooks 模块,用于跟踪异步资源的生命周期(Promise、setTimeout、fs、net 请求等)。

✅ 示例:追踪异步操作

const async_hooks = require('async_hooks');
const fs = require('fs');const hook = async_hooks.createHook({init(asyncId, type, triggerAsyncId, resource) {fs.writeSync(1, `[init] id: ${asyncId}, type: ${type}, trigger: ${triggerAsyncId}\n`);},before(asyncId) {fs.writeSync(1, `[before] id: ${asyncId}\n`);},after(asyncId) {fs.writeSync(1, `[after] id: ${asyncId}\n`);},destroy(asyncId) {fs.writeSync(1, `[destroy] id: ${asyncId}\n`);}
});hook.enable();setTimeout(() => {console.log('setTimeout done');
}, 100);

💡 输出示例:

[init] id: 6, type: Timeout, trigger: 1
[before] id: 6
setTimeout done
[after] id: 6
[destroy] id: 6

你可以看到异步资源从创建到销毁全过程。


🧪 2. 使用 perf_hooks 监控异步性能

perf_hooks 模块可以记录函数执行时间,适合性能调试:

const { performance, PerformanceObserver } = require('perf_hooks');performance.mark('start');setTimeout(() => {performance.mark('end');performance.measure('timeout duration', 'start', 'end');
}, 100);const obs = new PerformanceObserver((items) => {console.log(items.getEntries());
});obs.observe({ entryTypes: ['measure'] });

🕵️ 3. 使用 EventEmitter 自定义事件监测

Node 中很多异步库(如 httpfsnet)都继承自 EventEmitter,你可以自己监听事件触发:

const fs = require('fs');const stream = fs.createReadStream('./some.txt');stream.on('open', () => {console.log('stream opened');
});stream.on('data', (chunk) => {console.log(`chunk received: ${chunk.length} bytes`);
});stream.on('end', () => {console.log('stream ended');
});

🔍 4. 使用 APM 工具或监控平台

如果你做的是生产级应用,建议配合专业工具做异步事件监测:

  • Node Clinic:由 NearForm 开源的诊断工具

  • Elastic APM / New Relic / Datadog:可监控事件调用链、异步瓶颈

  • Chrome DevTools / VSCode:可远程调试 node --inspect


🧠 总结:不同监测方案对比

方式功能场景
async_hooks精确追踪所有异步资源生命周期调试复杂异步流程
perf_hooks性能度量和函数执行时间统计性能分析
EventEmitter捕捉异步事件本身(如 on(data), on(end))I/O 事件处理观察
DevTools / APM 工具图形化追踪调用栈生产监控、性能排查


是否需要我 结合一个实际的 Node 项目,演示如何用 async_hooks 追踪数据库、定时任务和网络请求的执行流?还是要我帮你分析你自己的项目异步流程?

三、NodeJS如何监测异步操作的时间

在 Node.js 中,监测异步操作的执行时间 是性能调优的常见需求,特别是在处理数据库查询、API 请求、文件操作等耗时操作时。下面是几种实用的方法,涵盖了从简单代码计时到底层异步性能钩子的全面方案。


✅ 方法一:使用 console.time() / console.timeEnd()(适合快速调试)

console.time('timer');setTimeout(() => {console.timeEnd('timer'); // 输出:timer: 100.123ms(示例)
}, 100);

优点:快速、轻便、零依赖
缺点:无法穿透异步调用链


✅ 方法二:使用 performancePerformanceObserver(推荐,适合结构化统计)

Node.js 提供的 perf_hooks 模块是内置性能监控工具。

const { performance, PerformanceObserver } = require('perf_hooks');performance.mark('start');setTimeout(() => {performance.mark('end');performance.measure('timeout_duration', 'start', 'end');
}, 100);const obs = new PerformanceObserver((items) => {console.log(items.getEntries()[0]); // { name: 'timeout_duration', duration: 100.xxx, ... }
});obs.observe({ entryTypes: ['measure'], buffered: true });

优势

  • 可标记多个时间点

  • 用于构建 Web 性能指标收集工具

  • 结构化输出,可聚合分析


✅ 方法三:使用 async_hooks 配合 executionAsyncId(适合深度追踪异步任务)

const async_hooks = require('async_hooks');
const { performance } = require('perf_hooks');const timings = new Map();const hook = async_hooks.createHook({init(asyncId, type, triggerAsyncId) {timings.set(asyncId, performance.now());},destroy(asyncId) {const start = timings.get(asyncId);if (start) {const duration = performance.now() - start;console.log(`[${asyncId}] async duration: ${duration.toFixed(2)} ms`);timings.delete(asyncId);}}
});hook.enable();// 异步操作
setTimeout(() => {console.log('setTimeout done');
}, 200);

注意:不要用 console.log 打印钩子内部内容,容易导致无限递归,用 fs.writeSync 更安全。


✅ 方法四:使用第三方库(可选)

工具库用途
newrelic / datadog / Elastic APM生产监控,链路追踪
node-clinicNearForm 出品,性能分析神器
why-is-node-running找出未结束的异步任务


✅ 方法五:手动嵌套 Date.now() 统计执行时长(最低成本方案)

const start = Date.now();fs.readFile('./test.txt', 'utf8', (err, data) => {const duration = Date.now() - start;console.log(`readFile took ${duration}ms`);
});

🧠 总结对比

方法精度易用性场景
console.time()毫秒级⭐⭐⭐⭐快速调试
performance + measure微秒级⭐⭐⭐正式代码推荐
async_hooks + Map微秒级⭐⭐全链路异步追踪
手动 Date.now()毫秒级⭐⭐⭐小型代码段
第三方 APM 工具微秒~ms⭐⭐企业级、生产环境监控


如果你想在自己的项目中实战一遍,比如:统计一次 HTTP 请求或数据库操作的精确耗时,并记录日志,我可以帮你写一个完整中间件或者封装工具函数,是否需要?

http://www.dtcms.com/a/251760.html

相关文章:

  • 「Matplotlib 入门指南」 Python 数据可视化分析【数据分析全栈攻略:爬虫+处理+可视化+报告】
  • 数据库相关操作
  • YOLOv11改进 | Conv/卷积篇 | 2024最新ECCV最新大感受野的小波卷积WTConv助力YOLOv11有效涨点(二次创新C3k2)
  • XXX2024073105:纪念品分组【c++】
  • 关于layui select option莫名多一行的问题
  • NodeJS哪些情况下会造成内存泄漏和避免方法
  • 建造者模式Builder Pattern
  • LeetCode HOT 100
  • ShenNiusModularity项目源码学习(34:总结)
  • 每日学习一道数模题-2024国赛E题-交通流量管控
  • React19源码系列之Hooks(useState)
  • C++ 类的知识点
  • 【Docker 05】Container - 容器
  • Spring AI的ChatClient和ChatModel接口
  • Node.js 中的 Token 认证机制详解
  • 动态规划之斐波那契数(一)
  • java 集合 泛型
  • (LeetCode 每日一题) 1432. 改变一个整数能得到的最大差值(贪心)
  • 编译链接实战(30)strip移除了哪些内容
  • JVM 类加载过程/对象创建过程/双亲委派机制/垃圾回收机制
  • 大模型微调(Fine-tuning)概览
  • Vue-Leaflet地图组件开发(四)高级功能与深度优化探索
  • 基于51单片机的温度和液位监测系统(串口传输)
  • Vue 性能优化
  • kicad运行时出错,_Pnext->_Myproxy = nullptr;访问内存出错
  • 自我实现的量子隐喻:在可能性场域中动态拓展涌现节点
  • 安装前端vite框架,后端安装fastapi框架
  • Multisim仿真Buck电路基本拓扑
  • 进程和线程区别、管道和套接字、共享变量、TCP三次握手,是否可以少一次握手、子进程和主进程区别和API——Nodejs
  • Spring Cloud Gateway 全面学习指南