前言
最近在看winter老师的重学前端,整理一下知识
为什么promise会先于setTimout执行呢?
先看这样一段代码,输出你的结果
let p = new Promise((resolve, reject) => {
console.log("a");
resolve() }
);
setTimeout(()=> console.log("d"), 0)
p.then(() => console.log("c"));
console.log("b")
// 执行结果: a => b => c
1.执行流程
我们都知道,JS代码是由上往下逐行解析的。
按这个逻辑在上面的例子中,我们得到如下顺序
- 声明了一个变量p
- setTimeout执行log,延迟是0ms
- 在p.then中执行log
- log('b')
但实际结果并不是这样的
首先,我们从这样个角度来看代码的执行过程
- 宿主拿到代码
- 内置的js引擎解析、编译代码
- 执行代码
- 处理执行过程中遇到的事件
- 如果是宿主提供的事件,比如DOM、IO等,把代码(函数)给到宿主
- 如果是引擎提供的,比如promise、nextTick,将任务push到当前执行栈的尾部
1.1什么是宿主对象?
宿主对象:
- 定义:执行JS脚本的环境(宿主)提供的对象。
- 特点:依赖于宿主,带来浏览器兼容问题,增加开发难度。
常见的宿主对象
- 浏览器中:window、documnent等
- Node中:global等
eg: 常见的setTimeout、setInterval实际上是宿主对象赋予我们使用的API,并不是JS自带的
1.2当碰到setTimeout、promise的时候
当遇到setTimeout
- 函数(代码)会通过事件的形式,将对应逻辑交还宿主操作处理
- 再解析代码、执行
实际上,当setTimeout的时候,其实我们使用宿主的API去执行了一次任务,所以,我们也把宿主任务叫做宏任务
当遇到promise
- promise是es5后引入的,作为js的一部分
- 由js发起一个任务,这个任务叫做微任务
实际上,当promise的时候,我们是通过js引擎发起的一个微任务
1.3promise不是setTimeout实现的吗?
细心的朋友可以会关注到promise的实现原理是通过setTimeout实现的,为什么不是宏任务?
答:我们只关注一件事,任务的发起者是谁?如果发起者是宿主对象,那就是宏任务,反之是JS引擎,那就是微任务。所以可以得到,其实我们并不关注内部原理,只关注发起动作的人是谁。
总结
- 由宿主发起的任务,是宏任务
- 由JS引擎发起的任务,是微任务
- 常见的setTimeout并不是JS内置的,而是宿主提供的