了解Node.js中的定时器
前两个含义和 web 上的是一致的,后两个是 Node.js 独有的,效果看起来就是 setTimeout(callback, 0),在 Node.js 编程中使用的最多
timers┌───────────────────────────┐ ┌─>│ timers │ │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ │ │ pending callbacks │ │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ │ │ idle, prepare │ │ └─────────────┬─────────────┘ ┌───────────────┐ │ ┌─────────────┴─────────────┐ │ incoming: │ │ │ poll │<─────┤ connections, │ │ └─────────────┬─────────────┘ │ data, etc. │ │ ┌─────────────┴─────────────┐ └───────────────┘ │ │ check │ │ └─────────────┬─────────────┘ │ ┌─────────────┴─────────────┐ └──┤ close callbacks │ └───────────────────────────┘
event loop 的每个阶段都有一个任务队列,当 event loop 进入给定的阶段时,将执行该阶段的任务队列,直到队列清空或执行的回调达到系统上限后,才会转入下一个阶段,当所有阶段被顺序执行一次后,称 event loop 完成了一个 tick
Timeout
定时器主要有两种Node.js 会在 timers 阶段检查是否有过期的 timer,如果存在则把回调放到 timer 队列中等待执行,Node.js 使用单线程,受限于主线程空闲情况和机器其它进程影响,并不能保证 timer 按照精确时间执行
idle, prepare:仅供系统内部调用
const EventEmitter = require('events'); const util = require('util'); function MyEmitter() { EventEmitter.call(this); this.emit('event'); } util.inherits(MyEmitter, EventEmitter); const myEmitter = new MyEmitter(); myEmitter.on('event', () => { console.log('an event occurred!'); });在构造函数执行 this.emit('event') 会导致事件触发比事件回调函数绑定早,使用 process.nextTick 可以轻松实现预期效果
当event loop进入 poll 阶段且没有被调度的计时器时
setImmediate(console.log, 1); setTimeout(console.log, 1, 2); Promise.resolve(3).then(console.log); /****************** 下次 event loop tick 分割线 ********************/ process.nextTick(console.log, 4); /****************** 同步任务和异步任务的分割线 ********************/ console.log(5);各个阶段主要任务
一个类继承了 EventEmitter,而且想在实例化的时候触发一个事件
计算应该阻塞和轮询 I/O 的时间
process.nextTick(callback[, ...args])
一旦 poll 队列为空,event loop 将检查 timer 队列是否为空,如果非空则进入下一轮 event loop
允许用户在 even tloop 开始之前 处理异常、执行清理任务
setTimeout(callback, delay[, ...args])
setInterval(callback[, ...args])
如果 poll 队列不是空的 ,event loop 将循环访问回调队列并同步执行,直到队列已用尽或者达到了系统或达到最大回调数
在 Node.js 环境下 microTask 会在每个阶段完成之间调用,也就是每个阶段执行最后都会执行一下 microTask 队列event loopNode.js 启动后会初始化事件轮询,过程中可能处理异步调用、定时器调度和 process.nextTick(),然后开始处理event loop。官网中有这样一张图用来介绍 event loop 操作顺序
Immediate
timers:执行 setTimeout、setInterval 回调
那么是不是编程中应该杜绝使用 process.nextTick 呢?官方推荐大部分时候应该使用 setImmediate,同时对 process.nextTick 的最大调用堆栈做了限制,但 process.nextTick 的调用机制确实也能为我们解决一些棘手的问题
上面提到了如果在不同的 I/O 里,不能确定 setTimeout 和 setImmediate 的执行顺序,但如果 setTimeout 和 setImmediate 在一个 I/O 回调里,肯定是 setImmediate 先执行,因为在 poll 阶段检查到有 setImmediate() 任务,event loop 直接进入 check 阶段执行 setImmediate 回调异步操作都被放到了下一个 event loop tick 中,process.nextTick 在进入下一次 event loop tick 之前执行,所以肯定在其它异步操作之前
如果没有 setImmediate()任务,event loop 阻塞在 poll 阶段等待回调被添加到队列中,然后立即执行
const EventEmitter = require('events'); const util = require('util'); function MyEmitter() { EventEmitter.call(this); // use nextTick to emit the event once a handler is assigned process.nextTick(() => { this.emit('event'); }); } util.inherits(MyEmitter, EventEmitter); const myEmitter = new MyEmitter(); myEmitter.on('event', () => { console.log('an event occurred!'); });更多编程相关知识,请访问:编程教学!!
以上就是了解Node.js中的定时器的详细内容,更多请关注聚合云库其它相关文章!
close callbacks:执行 socket 等的 close 事件回调
nextTick 1 nextTick 2 ... ... nextTick 999999 read file task done!于是乎需要一个不这么 bug 的调用,setImmediate 方法出现了,比较令人费解的是在 process.nextTick 起错名字的情况下,setImmediate 也用了一个错误的名字以示区分。。。
日常开发中绝大部分异步任务都是在 timers、poll、check 阶段处理的
然后,处理 poll 队列里的事件
check:setImmediate 回调在此阶段执行
如果 poll 队列是空的
如果有 setImmediate() 任务,event loop 会在结束 poll 阶段后进入 check 阶段
const fs = require('fs'); fs.readFile(__filename, () => { setTimeout(() => { console.log('timeout'); }, 0); setImmediate(() => { console.log('immediate'); }); });check在该阶段执行 setImmediate 回调
setImmediate(callback[, ...args])
同步 & 异步第五行是同步执行,其它都是异步的
setImmediate(console.log, 1); setTimeout(console.log, 1, 2); Promise.resolve(3).then(console.log); process.nextTick(console.log, 4); console.log(5);会打印 5 4 3 2 1 或者 5 4 3 1 2
允许回调在调用栈 unwind 之后,下次 event loop 开始之前执行
setTimeout(() => { console.log('timeout'); }, 0); setImmediate(() => { console.log('immediate'); });多次执行会发现打印的顺序不一样
setImmediate(console.log, 1);
setTimeout(console.log, 1, 2);
Promise.resolve(3).then(console.log);
process.nextTick(console.log, 4);
/****************** 同步任务和异步任务的分割线 ********************/
console.log(5);
所以先打印 5,这个很好理解,剩下的都是异步操作,Node.js 按照什么顺序执行呢?
setImmediate(console.log, 1);
setTimeout(console.log, 1, 2);
/****************** microTask 分割线 ********************/
Promise.resolve(3).then(console.log); // microTask 分割线
/****************** 下次 event loop tick 分割线 ********************/
process.nextTick(console.log, 4);
/****************** 同步任务和异步任务的分割线 ********************/
console.log(5);setImmediate VS process.nextTick
setImmediate 听起来是立即执行,process.nextTick 听起来是下一个时钟执行,为什么效果是反过来的?这就要从那段不堪回首的历史讲起
为什么 Promise.then 比 setTimeout 早一些前端同学肯定都听说过 micoTask 和 macroTask,Promise.then 属于 microTask,在浏览器环境下 microTask 任务会在每个 macroTask 执行最末端调用
pending callbacks:执行 I/O(文件、网络等) 回调
timer 用于安排函数在未来某个时间点被调用,Node.js 中的定时器函数实现了与 Web 浏览器提供的定时器 API 类似的 API,但是使用了事件循环实现,Node.js 中有四个相关的方法
Immediate 类型的计时器回调会在 check 阶段被调用,Timeout 计时器会在设定的时间过期后尽快的调用回调,但
const fs = require('fs'); fs.readFile('a.txt', (err, data) => { console.log('read file task done!'); }); let i = 0; function test(){ if(i++ < 999999) { console.log(`process.nextTick ${i}`); process.nextTick(test); } } test();执行程序将返回
最开始的时候只有 process.nextTick 方法,没有 setImmediate 方法,通过上面的分析可以看出来任何时候调用 process.nextTick(),nextTick 会在 event loop 之前执行,直到 nextTick 队列被清空才会进入到下一 event loop,如果出现 process.nextTick 的递归调用程序没有被正确结束,那么 IO 的回调将没有机会被执行
奇怪的执行顺序看一个示例,用几种方法分别异步打印一个数字
Node.js 不保证回调被触发的确切时间,也不保证它们的顺序,回调会在尽可能接近指定的时间被调用。setTimeout 当 delay 大于 2147483647 或小于 1 时,则 delay 将会被设置为 1, 非整数的 delay 会被截断为整数
poll
poll 阶段主要有两个任务
poll:获取新的 I/O 事件,执行相关回调,在适当条件下把阻塞 node
相关热词:
本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供用于网络技术学习参考,学习中请遵循相关法律法规!
本文地址: https://www.juheyunku.com/jiaob/javascript/4979.shtml
相关文章
热门TAG
服务器 命令 技巧 详解 调用 标签 功能 织梦 javascript dedecms修改内容 织梦教程 php 白帽 企业网站 外链 权重 MYSQL 网站流量 实例解析 JSP 网站收录 搜索引擎 蜘蛛 windows jquery jquery教程 python tags标签 HTML 织梦cms最新文章
-
Javascript是什么?
时间:2021-01-04
-
Canvas入门实战之实现一个
时间:2021-01-04
-
11月份GitHub上最热门的Ja
时间:2021-01-04
-
一篇带给你JavaScript的Cla
时间:2021-01-04
-
详解js异步文件加载器
时间:2021-01-04
-
深入理解JavaScript中的箭头
时间:2021-01-04
-
复盘Node项目中遇到的13+常
时间:2021-01-04
-
连续3年稳居第一,全球
时间:2021-01-04
热门文章
-
连续3年稳居第一,全球1240万用户,Java
时间:2021-01-04
-
一篇带给你JavaScript的Class语法介绍
时间:2021-01-04
-
深入理解JavaScript中的箭头函数
时间:2021-01-04
-
Javascript在Chrome浏览器中调试的七个步骤
时间:2021-01-04
-
Canvas入门实战之实现一个图形验证码
时间:2021-01-04
-
详解js异步文件加载器
时间:2021-01-04
-
复盘Node项目中遇到的13+常见问题和解决方
时间:2021-01-04
-
11月份GitHub上最热门的JavaScript开源项目
时间:2021-01-04
-
Javascript是什么?
时间:2021-01-04
