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 ...
随机推荐
- ie兼容问题整理
1.连续发请求问题 * jquery(document).ready(function(){}) * 连续发请求ie8出问题,被拦截问题,url后边加时间戳 * 例 url : url+ ...
- 【java基础】方法2
让形参可变的方法 jdk1.5之后,java允许定义形参长度可变的参数,允许为方法指定数量不确定的形参. package object; public class VariableParam { // ...
- 尽可能保留原有数据,建立UEFI与BIOS双启PE优盘
尽可能保留原有数据,建立UEFI与BIOS双启PE优盘1.确保优盘或者移动硬盘有一个FAT32分区,如果没有FAT32分区,就用傲梅分区助手或者ppm转换一个现有的分区到FAT32分区0x0C,或者新 ...
- 解决WCF的service端无法使用泛型的问题
思路是将其序列化(比较笨的方法……) 1.引入Newtonsoft.json.dll 2.服务端序列化:return JsonConvert.SerializeObject(result); 3.客户 ...
- git reset soft,hard,mixed之区别深解
GIT reset命令,似乎让人很迷惑,以至于误解,误用.但是事实上不应该如此难以理解,只要你理解到这个命令究竟在干什么. 首先我们来看几个术语 HEAD 这是当前分支版本顶端的别名,也就是在当前分支 ...
- html5-表单
例子: text,number,email 的输入框 <!-- required:必填项 --> <!-- autofocus:获得焦点 --> <!-- placeho ...
- 连接英文字符集的ORACLE和调用存储过程问题及64位服务器连接ORACLE问题
部署在IIS上的webservice连接英文字符集的ORACLE数据库出现问题“未在本地计算机上注册"MSDAORA.1"提供程序”,解决方案如下: 原因:如错误,64位系统未注册 ...
- C#微信公众号开发之网页授权oauth2.0获取用户基本信息(一)
咨询 请加 QQ::QQ群: 在微信里面,非认证的公众号账号,只能通过在微信回复菜单单击等事件获取openid,但是认证的公众账号(之前认证的订阅号是不可以的,现在新开放了政府媒体机构的认证订阅号)可 ...
- vs2008编译openssl问题
运行openssl demo 时,debug 版本正常,release 版本报异常:OPENSSL_Uplink(585E6000,08): no OPENSSL_Applink .demo 编译环境 ...
- mysqld.exe占比cpu 100% 解决方案
进入mysql命令行,输入show processlist; 查看当前有sql语句的记录