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 ...
随机推荐
- 转!!mysql order by 中文排序
1. 在MySQL中,我们经常会对一个字段进行排序查询,但进行中文排序和查找的时候,对汉字的排序和查找结果往往都是错误的. 这种情况在MySQL的很多版本中都存在. 如果这个问题不解决,那么MySQL ...
- php null o false ''
php中很多还不懂php中0,"",null和false之间的区别,这些区别有时会影响到数据判断的正确性和安全性,给程序的测试运行造成很多麻烦.先看一个例子: <? $str ...
- Linux系统资源监控命令
转自http://www.51testing.com/html/16/271416-149128.html 衡量CPU性能的指标: 1,用户使用CPU的情况:CPU运行常规用户进程CPU运行niced ...
- 51nod 1264 线段相交(几何)
题目链接:51nod 1264 线段相交 如果两条线段相交,则需满足一条线段的一个端点在另一条线段上,或者 两条线段都分别跨越另一条线段延伸的直线上.(如果点p1位于直线p3p4的一边,而点p2位于该 ...
- HashMap其实就那么一回事儿之源码浅析
上篇文章<LinkedList其实就那么一回事儿之源码分析>介绍了LinkedList, 本次将为大家介绍HashMap. 在介绍HashMap之前,为了方便更清楚地理解源码,先大致说说H ...
- easy ui datagrid 中getSelections方法只能获取一行数据
解决方案:设置 idField : "", // 设置标识
- [转]深入理解Java 8 Lambda(类库篇——Streams API,Collectors和并行)
以下内容转自: 作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://zh.lucida.me/blog/java-8-lambdas-insideout-l ...
- Mac OSX 无法SSH远程的原因
在mac中开启了远程共享,拿windows上的putty 死活无法ssh上去. 后来下载了个新版的putty, 连上了.
- Material Design之TextInputLayout使用示例
Google在2015的IO大会上,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的Android Design Support Library,在这个supp ...
- Spring Bean配置
Spring 是什么 •Spring 为简化企业级应用开发而生. 使用 Spring 可以使简单的 JavaBean 实现以前只有 EJB 才能实现的功能. •Spring 是一个 IOC(DI) 和 ...