详解promise.then,process.nextTick, setTimeout 以及 setImmediate的执行顺序


Posted in Javascript onNovember 21, 2018

本文介绍了详解promise.then,process.nextTick, setTimeout 以及 setImmediate的执行顺序,分享给大家,具体如下:

先举一个比较典型的例子:

setImmediate(function(){
  console.log(1);
},0);
setTimeout(function(){
  console.log(2);
},0);
new Promise(function(resolve){
  console.log(3);
  resolve();
  console.log(4);
}).then(function(){
  console.log(5);
});
console.log(6);
process.nextTick(function(){
  console.log(7);
});
console.log(8);

这段代码输出的正确顺序是什么?

答案是:

3 4 6 8 7 5 2 1

在解释输出结果之前,我们来看几个概念:

macro-task: script (整体代码),setTimeout, setInterval, setImmediate, I/O, UI rendering.

micro-task: process.nextTick, Promise(原生),Object.observe,MutationObserver

第一步. script整体代码被执行,执行过程为

  • 创建setImmediate macro-task
  • 创建setTimeout macro-task
  • 创建micro-task Promise.then 的回调,并执行script console.log(3); resolve(); console.log(4); 此时输出3和4,虽然resolve调用了,执行了但是整体代码还没执行完,无法进入Promise.then 流程。
  • console.log(6)输出6
  • process.nextTick 创建micro-task
  • console.log(8) 输出8
  • 第一个过程过后,已经输出了3 4 6 8

第二步. 由于其他micro-task 的 优先级高于macro-task。

此时micro-task 中有两个任务按照优先级process.nextTick 高于 Promise。

所以先输出7,再输出5

第三步,micro-task 任务列表已经执行完毕,家下来执行macro-task. 由于setTimeout的优先级高于setIImmediate,所以先输出2,再输出1。

整个过程描述起来像是同步操作,实际上是基于Event Loop的事件循环

关于micro-task和macro-task的执行顺序,可看下面这个例子(来自《深入浅出Node.js》):

//加入两个nextTick的回调函数
process.nextTick(function () {
  console.log('nextTick延迟执行1');
});
process.nextTick(function () { 
  console.log('nextTick延迟执行2');
});
// 加入两个setImmediate()的回调函数
setImmediate(function () {
  console.log('setImmediate延迟执行1'); 
  // 进入下次循环 
  process.nextTick(function () {
    console.log('强势插入');
  });
});
setImmediate(function () {
  console.log('setImmediate延迟执行2'); 
});

console.log('正常执行');

运行这段代码,结果是这样:

正常执行
nextTick延迟执行1
nextTick延迟执行2
setImmediate延迟执行1
setImmediate延迟执行2
强势插入

在新版的Node中,process.nextTick执行完后,会循环遍历setImmediate,将setImmediate都执行完毕后再跳出循环。所以两个setImmediate执行完后队列里只剩下第一个setImmediate里的process.nextTick。最后输出”强势插入”。

关于优先级的另一个比较清晰的版本:

观察者优先级

在每次轮训检查中,各观察者的优先级分别是:

idle观察者 > I/O观察者 > check观察者。

idle观察者:process.nextTick

I/O观察者:一般性的I/O回调,如网络,文件,数据库I/O等

check观察者:setTimeout>setImmediate

总结

  • 同步代码执行顺序优先级高于异步代码执行顺序优先级;
  • new Promise(fn)中的fn是同步执行;
  • process.nextTick()>Promise.then()>setTimeout>setImmediate。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript innerHTML、outerHTML、innerText、outerText的区别
Nov 24 Javascript
JavaScript Event学习第九章 鼠标事件
Feb 08 Javascript
让你的博客飘雪花超出屏幕依然看得见
Jan 04 Javascript
javascript去掉代码里面的注释
Jul 24 Javascript
Kindeditor在线文本编辑器如何过滤HTML
Apr 14 Javascript
js/jquery控制页面动态加载数据 滑动滚动条自动加载事件的方法
Feb 08 Javascript
js实现网页定位导航功能
Mar 07 Javascript
JavaScript实现多重继承的方法分析
Jan 09 Javascript
layer弹出框确定前验证:弹出消息框的方法(弹出两个layer)
Sep 21 Javascript
解决vue-router 二级导航默认选中某一选项的问题
Nov 01 Javascript
使用JavaScript实现贪吃蛇游戏
Sep 29 Javascript
vue使用localStorage持久性存储实现评论列表
Apr 14 Vue.js
Nuxt.js之自动路由原理的实现方法
Nov 21 #Javascript
nuxt.js中间件实现拦截权限判断的方法
Nov 21 #Javascript
Nuxt.js SSR与权限验证的实现
Nov 21 #Javascript
详解nuxt路由鉴权(express模板)
Nov 21 #Javascript
使用vue-cli webpack 快速搭建项目的代码
Nov 21 #Javascript
Angular刷新当前页面的实现方法
Nov 21 #Javascript
详解ES6系列之私有变量的实现
Nov 21 #Javascript
You might like
简单实现限定phpmyadmin访问ip的方法
2013/03/05 PHP
php常用Stream函数集介绍
2013/06/24 PHP
php一维二维数组键排序方法实例总结
2014/11/13 PHP
学习php设计模式 php实现访问者模式(Visitor)
2015/12/07 PHP
ThinkPHP中create()方法自动验证实例
2017/04/26 PHP
PHP实现将几张照片拼接到一起的合成图片功能【便于整体打印输出】
2017/11/14 PHP
PHP验证类的封装与使用方法详解
2019/01/10 PHP
Jquery easyui 下loaing效果示例代码
2013/08/12 Javascript
简单漂亮的js弹窗可自由拖拽且兼容大部分浏览器
2013/10/22 Javascript
Nodejs sublime text 3安装与配置
2014/06/19 NodeJs
EasyUI实现二级页面的内容勾选的方法
2015/03/01 Javascript
分享javascript计算时间差的示例代码
2020/03/19 Javascript
JavaScript数组的一些奇葩行为
2016/01/25 Javascript
jQuery获取复选框被选中数量及判断选择值的方法详解
2016/05/25 Javascript
AngularJS教程 ng-style 指令简单示例
2016/08/03 Javascript
Bootstrap字体图标无法正常显示的解决方法
2016/10/08 Javascript
AngularJs 延时器、计时器实例代码
2017/09/16 Javascript
JS实现百度网盘任意文件强制下载功能
2018/08/31 Javascript
微信小程序如何调用json数据接口并解析
2019/06/29 Javascript
Angular利用HTTP POST下载流文件的步骤记录
2020/07/26 Javascript
[48:31]完美世界DOTA2联赛PWL S3 DLG vs Phoenix 第二场 12.17
2020/12/19 DOTA
Python获取CPU、内存使用率以及网络使用状态代码
2018/02/08 Python
python实现按长宽比缩放图片
2018/06/07 Python
python多进程间通信代码实例
2019/09/30 Python
Python从列表推导到zip()函数的5种技巧总结
2019/10/23 Python
谈一谈数组拼接tf.concat()和np.concatenate()的区别
2020/02/07 Python
对django 2.x版本中models.ForeignKey()外键说明介绍
2020/03/30 Python
Python调用.net动态库实现过程解析
2020/06/05 Python
Python爬虫教程知识点总结
2020/10/19 Python
方法名是否可以与构造器的名字相同
2012/06/04 面试题
感恩寄语大全
2014/04/11 职场文书
给下属加薪申请报告
2015/05/15 职场文书
黑白记忆观后感
2015/06/18 职场文书
退休欢送会主持词
2015/07/01 职场文书
你真的了解PHP中的引用符号(&)吗
2021/05/12 PHP
关于Numpy之repeat、tile的用法总结
2021/06/02 Python