JavaScript tasks, microtasks, queues and schedules
最近做的项目中,涉及到了JavaScript中Promise的用法,于是做了一点测试,发现没有想象中的那么简单,水很深,所以找来N先生(我的Mentor),想得到专业的指导。N先生也不尽知,但N先生查源码能力了不起,一小时之内解决了问题,还给我了一篇英文参考文献,拜读后,觉得有必要写一篇随笔,记录所得。
一. 问题
如果输入以下代码,会得到什么样的输出结果?如果连N先生这样在这个行业内浸染了12年的人都无法在最初给出正确的话,想必很多人还是很难回答正确的。不过在看下面的内容前,不妨猜测一下:D
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
正确的顺序为:
script start script end promise1 promise2 setTimeout
当然由于不同浏览器支持的问题,在某些特定版本的浏览器下,setTimeout会在promise1,pormise2的前面,比如Microsoft Edge, Firefox 40, iOS Safari 和 desktop Safari 8.0.8。
这看起来像是资源竞争(race condition)的问题,但实际上并不是。
二. 为什么会是以上的顺序
要理解为什么是以上的顺序发生,我们需要掌握事件队列(event loop)是如何处理JavaScript Tasks 和 microtasks的。如果你是第一次碰到这个问题,那么,请深吸一口气,接着往下看:D
每个工作线程(Web worker)都有自己的事件队列,他们各自相互不影响,每个线程的事件队列,都会对进队的tasks任务进行处理。如果有很多的task在一个工作线程的队列里等待处理,那么,需要由浏览器来决定执行的先后顺序。
这时,浏览器就可以给那些性能敏感(performance sensitive)的task优先权,比如对用户输入的反应。
Tasks会被排定好,于是browser可以按顺序将它带给JavaScript/DOM。在task和task的中间,浏览器或许会渲染更新。比如鼠标点击的回调函数就可以排定一个task,再比如,setTimeOut。
setTimeOut会在给定的时间之后,对回调函数排定一个Task,script end是第一个task,而setTimeout是独立的另一个task,这也就是为什么setTimeout会在scrript end之后输出。
Mircrotasks经常会被排定在当前执行脚本结束之后立即执行,这样的task比如想把事情做成异步,但又不想建立一个全新的task。Microtasks queue会在当前没有JavaScript事件正在执行,并且已经到了每个task结束的时候处理。任何新入队的microtask在正在执行microtask queue时,也会被马上处理。在以上的例子中,promise的回调函数就是microtask。
一旦一个promise解决了,它会将自己的回调函数加入microtask queue。这保证了即使promise及时解决了,它的回调函数还是异步执行的。这就是为什么promise1,promise2为什么在script end后面执行。Microtask总是在下一个task开始前发生。
三. 为什么有些浏览器会有不同的表现呢
其实是因为“将promise作为task还是microtask引起的”。针对这个已经有了很多的讨论,但舆论基本是同意将promise作为microtask的。理由我就不列了,相信大家也能自己琢磨的到:D
Cheers,
You have a nice day!
Lei
JavaScript tasks, microtasks, queues and schedules的更多相关文章
- [Javascript] Use requestIdleCallback to schedule JavaScript tasks at an optimal time
JavaScript is single-threaded, which can present some problems when creating an interactive user exp ...
- 深入理解 JavaScript 事件循环(二)— task and microtask
引言 microtask 这一名词是 JS 中比较新的概念,几乎所有人都是在学习 ES6 的 Promise 时才接触这一新概念,我也不例外.当我刚开始学习 Promise 的时候,对其中回调函数的执 ...
- javascript引擎执行的过程的理解--执行阶段
一.概述 同步更新sau交流学习社区(nodeJSBlog):javascript引擎执行的过程的理解--执行阶段 js引擎执行过程主要分为三个阶段,分别是语法分析,预编译和执行阶段,上篇文章我们介绍 ...
- 深入理解JavaScript事件循环机制
前言 众所周知,JavaScript 是一门单线程语言,虽然在 html5 中提出了 Web-Worker ,但这并未改变 JavaScript 是单线程这一核心.可看HTML规范中的这段话: To ...
- 每个JavaScript工程师都应懂的33个概念
摘要: 基础很重要啊! 原文:33 concepts every JavaScript developer should know 译文:每个 JavaScript 工程师都应懂的33个概念 作者:s ...
- [译] 深入理解 JavaScript 事件循环(二)— task and microtask
引言 microtask 这一名词是 JS 中比较新的概念,几乎所有人都是在学习 ES6 的 Promise 时才接触这一新概念,我也不例外.当我刚开始学习 Promise 的时候,对其中回调函数的执 ...
- 每个 JavaScript 工程师都应懂的33个概念
简介 这个项目是为了帮助开发者掌握 JavaScript 概念而创立的.它不是必备,但在未来学习(JavaScript)中,可以作为一篇指南. 本篇文章是参照 @leonardomso 创立,英文版项 ...
- 从event loop规范探究javaScript异步及浏览器更新渲染时机
异步的思考 event loops隐藏得比较深,很多人对它很陌生.但提起异步,相信每个人都知道.异步背后的“靠山”就是event loops.这里的异步准确的说应该叫浏览器的event loops或者 ...
- 总结:JavaScript异步、事件循环与消息队列、微任务与宏任务
本人正在努力学习前端,内容仅供参考.由于各种原因(不喜欢博客园的UI),大家可以移步我的github阅读体验更佳:传送门,喜欢就点个star咯,或者我的博客:https://blog.tangzhen ...
随机推荐
- NHibernate的使用
本文档适合初级开发者或者是第一次接触NHibernate框架的朋友,其中NHibernate不是最新的版本,但是一个比较经典的版本 NHibernate 2.1.2,其中用红线标注的部分一定要仔细看, ...
- 基于注解的Spring AOP的配置和使用--转载
AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程.可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. ...
- Spring <bean> 参数意义
1.id bean的唯一标识, 2.class 类的完全限定名, 3.parent 父类bean定义的名字. 如果没有任何声明,会使用父bean,但是也可以重写父类.重写父类时,子bean 必须与父b ...
- Android DisplayMetrics类获取屏幕大小
DisplayMetrics public class DisplayMetrics extends Object java.lang.Object ↳ android.util.Disp ...
- 在centos中安装jenkins master测试环境
在centos中安装jenkins 1)安装目录 pwd (/home/AAA) 2)检查java是否安装 [AAA@Centos_AAA jenkins]$ java -version j ...
- Objective-C( Foundation框架 一 常见的结构体)
常见的结构体 (NSPoint,CGPoint).(NSRange,CGRange).(NSSize,CGSize) 苹果官方推荐使用CG开头的结构体 NSRange是Foundation框架中常见的 ...
- escape()、encodeURI()、encodeURIComponent()区别详解--zt
JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,decod ...
- to my friends-Don't give up so fast
早上听到大学挺要好的朋友突然说要换行,心情就一股莫名的哀伤,因为当初是三个人一起约定好的,要朝着我们共同的目标而努力奋斗的,这股热情怎能这么轻易地被现实的冷水浇灭.没错,我们是刚出社会的毛头小子,我们 ...
- 安装Pod时提示ERROR: While executing gem ... (Errno::EPERM) Operation not permitted - /usr/bin/pod
环境:OSX EI 10.11.1 昨天切换gem源后,招待pod安装没有任何问题,也可以正常用$ gem sources --add https://ruby.taobao.org/ --remov ...
- CentOs6.5下独立安装Nginx篇
一.检查系统是否安装了Nginx [root@localhost local]# find -name nginx [root@localhost local]# (如果已经安装了nginx就卸载掉原 ...