理解promise、async 和await之间的执行关系
栏目: JavaScript · 发布时间: 5年前
内容简介:先看下面的例子执行结果如下:注意:在新的浏览器中打印的结果不是这样,是下面的样子
先看下面的例子
console.log('script start'); async function async1(){ console.log('async1 start'); await async2(); console.log('async1 end'); } async function async2(){ console.log('async2 end'); } async1(); setTimeout(function(){ console.log('setTimeout'); },0) new Promise(resolve=>{ console.log('Promise'); resolve(); }).then(function(){ console.log('promise1'); }) console.log('script end'); 复制代码
执行结果如下:
script start async1 start async2 end Promise script end promise1 async1 end setTimeout 复制代码
注意:在新的浏览器中打印的结果不是这样,是下面的样子
为什么会不一样? 我们先简单说一下是v8团队借鉴了node8中的一个Bug,为了提升性能,在引擎底层将三次tick减少到了2次。但是这样做违反了规范,不过规范也是人制定的,是可以在一定情况下,修改的。 传送门 ,想了解的可以看这里
我们还是按照规范理解上面的打印结果
- 1.首先打印出script start (这个就不讲了)
- 2.执行到async1()的时候,首先会打印出async1 start,因为async表达式定义的函数也是立即执行的
- 3.然后执行到await async2(),发现saync2也是个async定义的函数,所以直接执行 async2 end,同时async2返回一个Promise, 重点:此时返回的Promise会被放入到回调队列中等待,await会让出线程(js是单线程的),接下来跳出async1函数,继续往下执行 ;
- 4.然后执行到setTimeout,setTimeout是宏任务,会等到执行栈(调用栈)清空之后,微任务全部执行完毕之后,才会去执行,所以setTimeout会被挂起,最后执行
- 5.然后到了new Promise,new Promise是立即执行的,所以会立即打印出Promise;(Promise是一个立即执行的函数,但是它的成功(resolve())或失败(reject())回调函数确实一个异步执行的回调。) 然后执行resolve()的时候,resolve()这个任务会被放入回调队列中,等到调用栈有空闲的时候,事件循环(Event Loop)再来取走它 , 这时候会跳出Promise,继续往下走
- 6.输出script end;
- 7.同步任务已经全部执行完毕,执行栈现在已经空闲出来,那么事件循环就会去回调队列中取任务继续放到执行栈中执行;
- 8.这时候取的第一个任务就是async2放进去的Promise,执行Promise的时候遇到了resolve函数, resolve又回被放入到任务队列中继续等待,然后再次跳出async1 继续下一个任务
- 9.接下来取走的就是new Promise放进去的resolve回调,这个被调用栈执行,并输出promise1,然后继续取下一个任务
- 10.这次终于取到了那么Promise的resolve回调,因为async2并没有return内容,所以这个resolve的参数是undefined,此时await定义的Promise已经执行完毕并且返回了结果,所以可以继续往下执行async1函数后面的任务了,于是输出async1 end
- 11.上面的微任务执行完毕之后,开始执行宏任务中的异步setTimeout
总结:Event Loop 执行顺序如下:
- 1 首先执行同步任务,这属于宏任务
- 2.当执行完所有同步任务代码之后,执行栈为空,查询是否有异步代码需要执行
- 3.执行所有微任务
- 4.当执行完所有微任务后,如果有必要会渲染页面
- 5.然后开始下一轮的Event Loop,执行宏任务中的异步代码,也就是setTimeout中的回调函数
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。