当同时存在Promise
与setTimeOut
时,它们的执行顺序是什么呢?
作为浏览器或者运行环境,在拿到开发者给的JavaScript的代码后,首先要传递给JavaScript引擎,让其执行。但是JavaScript的运行,往往需要时间,这时候就需要一个认知,一个JavaScript引擎会常驻内存,等待我们将代码或者函数传递给它。
es3及之后
在早期,JavaScript没有异步执行的概念,当传递代码时,往往是顺序执行宿主(浏览器)发起的任务。
es5之后,JavaScript引入了Promise
,JavaScript可以发起任务,而不需要浏览器的安排。
这里浏览器发起的任务为宏观任务,JavaScript引擎发起的任务为微观任务。
宏观任务与微观任务
JavaScript引擎等待宿主分配宏观任务,在操作系统中,等待行为称为事件循环。
简单来讲就是“等待” - “执行”。这里省略了判断循环是否结束,宏观队列的问题。
1 | while(TRUE){ |
每次的执行过程,就是一个宏观任务,事件的循环也可以称为宏观任务队列。
在宏观任务中,JavaScript会执行Promise
异步代码。JavaScript要保证代码在宏观任务里执行,因此宏观任务包含一个微观任务队列。
有了宏观任务和微观任务,就可以实现JavaScript的引擎和宿主任务了。这里,Promise
永远在队列尾部添加微观任务,setTimeOut
等宿主API,则添加宏观任务。
Promise
Promise
是 JavaScript 语言提供的一种标准化的异步管理方式,它的总体思想是,需要进行 io、等待或者其它异步操作的函数,不返回真实结果,而返回一个“承诺”,函数的调用方可以在合适的时机,选择等待这个承诺兑现(通过 Promise
的 then 方法的回调)。
执行顺序分析:
- 分析几个宏观任务
- 确定每个宏观任务里有几个微观任务
- 根据调用顺序,确定微观任务执行顺序
- 确定宏观任务顺序
1 | setTimeout(()=>console.log("d"), 0) |
asyc/await
es6新引入的特性,其运行基础为Promise
,asyc
函数必须返回Promise
,返回的Promise
即为异步函数。
async 函数是一种特殊语法,特征是在 function 关键字之前加上 async 关键字,这样,就定义了一个 async 函数,我们可以在其中使用 await 来等待一个 Promise
。
其强大之处在于可以嵌套。
1 | // 盒子绿三秒,黄1秒,红三秒 |