~先双手奉上这道题目~promise
async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); } async function async2() { console.log( 'async2'); } console.log("script start"); setTimeout(function () { console.log("settimeout"); },0); async1(); new Promise(function (resolve) { console.log("promise1"); resolve(); }).then(function () { console.log("promise2"); }); console.log('script end');
JS众所周知是单线程语言,Javascript引擎同一时刻只能执行一个代码块,使用Event Loop做为它的异步执行机制浏览器
那么Event Loop是如何实现异步呢,我的浅显的理解以下:异步
等主进程中的同步函数执行完毕后,轮询去执行异步队列中的异步函数async
⚠️注意: setTimeOut并非直接的把你的回掉函数放进上述的异步队列中去,而是在定时器的时间到了以后,把回掉函数放到执行异步队列中去。若是此时这个队列已经有不少任务了,那就排在他们的后面。这也就解释了为何setTimeOut为何不能精准的执行的问题了。setTimeOut执行须要知足两个条件:函数
1. 主进程必须是空闲的状态,若是到时间了,主进程不空闲也不会执行你的回掉函数 2. 这个回掉函数须要等到插入异步队列时前面的异步函数都执行完了,才会执行
理解了Eventloop异步实现的方式,再来补充一下promise、async/awaitoop
首先,new Promise是同步的任务,会被放到主进程中去当即执行。而.then()函数是异步任务会放到异步队列中去,那何时放到异步队列中去呢?当你的promise状态结束的时候,就会当即放进异步队列中去了。若是你要问他和setTimeOut谁当进去的快,要从下面两个方面考虑:线程
1. promise结束时。.then内函数插入异步队列的时间与setTimeOut的回掉函数插入队列的时间,谁的早,谁的就最快 2. **若是promise是同步的而setTimeOut时间是0,那么是promise先执行**。至于什么,查了不少的资料,了解到:一个浏览器环境只能有一个事件循环,而一个事件循环能够有多个任务队列。settimeout所在的队列与promise.then()的队列不一样,面对此种状况,v8实现的时候会先从promise.then()的队列取任务,可是并无很理解,若是有大佬愿意指点迷津,请留言告知🙏
接下来,带着上面的那些总结,步入正题code
分析上述的代码,给任务类型分类对象
async function async1() { console.log( 'async1 start’ ) // 同步代码2 await async2() // 执行async2 console.log( 'async1 end’ ) // 须要等async1外面的代码执行完,而且async2也执行完才会执行 } async function async2() { console.log( 'async2’ ) // 同步代码3 } // ===================== 从这里开始了表演,因此在这里走起 =============================== console.log( 'script start’ ) // 同步代码1 setTimeout( function () { // setTimeout放入event-loop中的macro-tasks队列,暂不执行 console.log( 'setTimeout' ) }, 0 ) async1() // 若是有await,第一个【await前面的代码】属于主进程执行—看最上面函数内分析 new Promise( function ( resolve ) { // 注意这个方法里面的是同步 // 同步代码4 console.log( 'promise1’ ) resolve(); } ).then( // .then()放入event-loop中的micro-tasks队列 function () { console.log( 'promise2' ) } ) console.log( 'script end’ ) // 同步代码5
最早输出的是同步代码,按照上下文执行顺序是排序
'script start’ 'async1 start’ 'async2’ 'promise1’ 'script end’
第一个执行的函数是async1() ,里面有await,他要等待,等待就是要让async外面的代码先执行,外面的那些同步代码执行好了以后,在执行这个async里面的,await后面的代码执行。因此遇到await就让出了线程,给到后面的代码,那么下面的promise.then
会先执行,后执行await后面的代码
async1()的await后面和setTimeOut哪一个先执行,这个要看await等待的是什么。此处等待的是async2函数,这个函数里面没有await等待,带async
关键字的函数返回的是一个promise对象,因此async1中等待的是一个promise对象,而且这个promise对象里面只有同步执行,会被放进时间循环的micro-tasks队列,该队列比setTimeOut的队列先执行,执行完了以后还不能执行setTimeOut,由于执行完了以后就不阻塞主进程了,主进程要接着执行;也就是await后面的同步代码,要先去执行主进程。因此setTimeOut是在最后执行的
再次验证了上面所说的setTimeOut执行的必要条件之一是主进程空闲了
所以,异步代码的执行顺序是
‘promise2' // async函数外的代码先执行 'async1 end’ // -- await不阻塞了,async后面的同步代码 'setTimeout' // promise.then的队列比setTimeout队列先执行
若是你真正的理解了Event Loop的执行机制,而且知道setTimeout的与promise.then并不是一个队列里面的,那么这道题就是很简单的送分题
上述若有不足或者不当指出,请各位大佬匡正~~💗