详解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 相关文章推荐
jquery实用代码片段集合
Aug 12 Javascript
屏蔽script注入小例子
Nov 12 Javascript
JS关键字球状旋转效果的实例代码
Nov 29 Javascript
jQuery html()方法使用不了无法显示内容的问题
Aug 06 Javascript
JavaScript动态修改弹出窗口大小的方法
Apr 06 Javascript
快速解决js开发下拉框中blur与click冲突
Oct 10 Javascript
JavaScript实现移动端轮播效果
Jun 06 Javascript
React Native验证码倒计时工具类分享
Oct 24 Javascript
angular中不同的组件间传值与通信的方法
Nov 04 Javascript
详解Require.js与Sea.js的区别
Aug 05 Javascript
详解js删除数组中的指定元素
Oct 31 Javascript
Nuxt.js开启SSR渲染的教程详解
Nov 30 Javascript
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
php 保留小数点
2009/04/21 PHP
php生成扇形比例图实例
2013/11/06 PHP
php自定义加密与解密程序实例
2014/12/31 PHP
PHP实现通过正则表达式替换回调的内容标签
2015/06/15 PHP
CI框架的安全性分析
2016/05/18 PHP
PHP  Yii清理缓存的实现方法
2016/11/10 PHP
thinkPHP5.0框架验证码调用及点击图片刷新简单实现方法
2018/09/07 PHP
Ubuntu 16.04中Laravel5.4升级到5.6的步骤
2018/12/07 PHP
JavaScript 高级篇之DOM文档,简单封装及调用、动态添加、删除样式(六)
2012/04/07 Javascript
JS原型对象通俗"唱法"
2012/12/27 Javascript
基于JavaScript实现TAB标签效果
2016/01/12 Javascript
jquery ztree异步搜索(搜叶子)实践
2016/02/25 Javascript
Struts2+jquery.form.js实现图片与文件上传的方法
2016/05/05 Javascript
限制复选框最多选择项的实现代码
2016/05/30 Javascript
vuejs绑定class和style样式
2017/04/11 Javascript
JQuery form表单提交前验证单选框是否选中、删除记录时验证经验总结(整理)
2017/06/09 jQuery
详解jquery插件jquery.viewport.js学习使用方法
2017/09/08 jQuery
你点的 ES6一些小技巧,请查收
2018/04/25 Javascript
微信小程序用户信息encryptedData详解
2018/08/24 Javascript
亲自动手实现vue日历控件
2019/06/26 Javascript
layer父页获取弹出层输入框里面的值方法
2019/09/02 Javascript
Vue.extend 编程式插入组件的实现
2019/11/18 Javascript
ES6如何用一句代码实现函数的柯里化
2020/01/18 Javascript
分析并输出Python代码依赖的库的实现代码
2015/08/09 Python
详谈python中冒号与逗号的区别
2018/04/18 Python
为何人工智能(AI)首选Python?读完这篇文章你就知道了(推荐)
2019/04/06 Python
tensorflow 模型权重导出实例
2020/01/24 Python
python统计mysql数据量变化并调用接口告警的示例代码
2020/09/21 Python
丝芙兰中国官方商城:SEPHORA中国
2018/01/10 全球购物
美国在线打印网站:Overnight Prints
2018/10/11 全球购物
介绍Java的内部类
2012/10/27 面试题
市场营销个人求职信范文
2014/02/02 职场文书
村庄绿化方案
2014/05/07 职场文书
工程项目经理任命书
2014/06/05 职场文书
医院标语大全
2014/06/23 职场文书
校外活动方案
2014/08/28 职场文书