【Js运行时一】宏任务、微任务的发起者

606 阅读2分钟

前言

最近在看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内置的,而是宿主提供的