// resultrun main threadtick taskpromise resolvetimer tasktick task in timeouttick task in timeout->tickpromise resolve in timeouttick task in timeout promiseimmediate taskimeediate->tick task现在解读一下以上的执行流程:
NodeJS 在经过一系列初始化工作后,开始执行用户 JS 代码,解释执行过程中,分别把 setTimeout、setImmediate、Promise、nextTick 函数的回调插入 timer、immediate、microtask 和 nexttick 队列 。
- 执行主线程 console.log("run main thread"),打印 "run main thread"
- 进入 timer 阶段前,发现 nextTick 、promise 队列有任务如下:
nextTicks = [() => {console.log("tick task");}];microtasks = [() => {console.log('promise resolve');}];分别打印 "tick task" 以及 "promise resolve"- 进入 timer 阶段,执行定时器回调,定时器回调中再次往 microtask 和 nextTick 插入新的任务如下:
nextTicks = [() => {console.log('tick task in timeout');process.nextTick(() => {console.log("tick task in timeout->tick");})}];microtasks = [() => {console.log('promise resolve in timeout');process.nextTick(() => {console.log('tick task in timeout promise');});}];打印主线程任务中的 "timer task",再进入下一阶段,发现 nextTicks 和 microtasks 队列为非空,执行微任务 。由于 nextTicks 优先级更高,先打印 "tick task in timeout",然后又往 nextTicks 插入 () => {console.log("tick task in timeout->tick")} ,继续执行 nextTicks 任务打印 "tick task in timeout->tick" 。此时 nextTicks 队列已空,执行 miacrotasks 队列,打印 "promise resolve in timeout",此时又往 nextTicks 插入任务 () => {console.log('tick task in timeout promise')}?,继续执行 nextTick 任务,打印 "tick task in timeout promise" 。
进入 check 阶段(Immediate),为 nextTicks 添加 () => {console.log('imeediate->tick task') }?,主线程打印 "immediate task",进入下一阶段前先执行 nextTicks 任务,打印 'imeediate->tick task' 。
?拓展?
setImmediate(() => console.log('this is set immediate 1'));setImmediate(() => console.log('this is set immediate 2'));setImmediate(() => console.log('this is set immediate 3'));setTimeout(() => console.log('this is set timeout 1'), 0);setTimeout(() => {console.log('this is set timeout 2');process.nextTick(() => console.log('this is process.nextTick added inside setTimeout'));}, 0);setTimeout(() => console.log('this is set timeout 3'), 0);setTimeout(() => console.log('this is set timeout 4'), 0);setTimeout(() => console.log('this is set timeout 5'), 0);process.nextTick(() => console.log('this is process.nextTick 1'));process.nextTick(() => {process.nextTick(console.log.bind(console, 'this is the inner next tick inside next tick'));});process.nextTick(() => console.log('this is process.nextTick 2'));process.nextTick(() => console.log('this is process.nextTick 3'));process.nextTick(() => console.log('this is process.nextTick 4'));I/O 模型得益于 Libuv 这一跨平台的高性能异步 I/O 库,使得 NodeJS 在处理 I/O 密集型任务上十分彰显优势 。下面结合不同的 I/O 模型,对比分析一下 NodeJS 目前工程实践所采用的 I/O 模型的优越性 。首先理清一下阻塞和非阻塞、异步和同步的概念:
- 阻塞和非阻塞
- 异步和同步
?同步阻塞?图片来源:https://www.51cto.com/article/693213.html
在网络编程中,当调用 recvfrom 获取客户端数据时,首先会阻塞进程,等待数据通过网卡到内核缓冲区;当数据就绪后,再同步等待指代数据从内核缓冲区拷贝到用户空间,此时用户进程再进行数据处理 。
同步阻塞 I/O 模型是最简单的 I/O 模型,好处是使用简单,通常在 fd 较少、数据就绪很快的场景,缺点是如果内核数据一直没准备好,则用户进程将会一直阻塞无法执行后续任务 。
推荐阅读
- 十个优质的基于Node.js的CMS 内容管理平台
- Linux系统下如何设置开机自动运行脚本?
- 如何寻找并删除系统里的重复文件,快速释放磁盘空间?
- 用了三年MySQL,还不知道Server层和引擎层是如何交互的?
- 如何提升HTTPS访问速度?网站HTTPS性能优化技巧
- Ngnix如何配置强制HTTPS访问?
- 机器学习系统架构的十个要素
- 从如何更好的监控Oracle共享池谈起
- 如何以及为什么衡量网络安全
- Java 中为什么要设计 throws 关键词,是故意的还是不小心
