从一道题目登程
明天看到一道面试题,是对于async/await、promise和setTimeout的执行程序,题目如下:
async function async1() {console.log('async1 start');await async2();console.log('asnyc1 end');}async function async2() {console.log('async2');}console.log('script start');setTimeout(() => {console.log('setTimeOut');}, 0);async1();new Promise(function (reslove) {console.log('promise1');reslove();}).then(function () {console.log('promise2');})console.log('script end');
我给出的答案:
script startasync1 startasync2asnyc1 end // xpromise1script endpromise2setTimeOut
正确的答案:
script startasync1 startasync2promise1script endasnyc1 endpromise2setTimeOut
为什么promise1比asnyc1 end先进去呢?带着这个疑难,我去理解了一下事件循环机制。
js EventLoop 事件循环机制
JavaScript的事件分两种:
事件的执行程序,是先执行宏工作,而后执行微工作,这个是根底,工作能够有同步工作和异步工作,同步的进入主线程,异步的进入Event Table并注册函数,异步事件实现后,会将回调函数放入Event Queue中(宏工作和微工作是不同的Event Queue),同步工作执行实现后,会从Event Queue中读取事件放入主线程执行,回调函数中可能还会蕴含不同的工作,因而会循环执行上述操作。
留神: setTimeOut并不是间接的把你的回掉函数放进上述的异步队列中去,而是在定时器的工夫到了之后,把回掉函数放到执行异步队列中去。如果此时这个队列曾经有很多工作了,那就排在他们的前面。这也就解释了为什么setTimeOut为什么不能精准的执行的问题了。setTimeOut执行须要满足两个条件:
主过程必须是闲暇的状态,如果到工夫了,主过程不闲暇也不会执行你的回调函数
这个回调函数须要等到插入异步队列时后面的异步函数都执行完了,才会执行
promise、async/await
首先,new Promise是同步的工作,会被放到主过程中去立刻执行。而.then()函数是异步工作会放到异步队列中去,那什么时候放到异步队列中去呢?当你的promise状态完结的时候,就会立刻放进异步队列中去了。
带async关键字的函数会返回一个promise对象,如果外面没有await,执行起来等同于一般函数;如果没有await,async函数并没有很厉害是不是。
await 关键字要在 async 关键字函数的外部,await 写在里面会报错;await如同他的语意,就是在期待,期待右侧的表达式实现。此时的await会让出线程,阻塞async内后续的代码,先去执行async外的代码。等里面的同步代码执行结束,才会执行外面的后续代码。就算await的不是promise对象,是一个同步函数,也会等这样操作。
流程梳理
咱们整体再梳理一下下面代码执行的流程:
整个代码片段(script)作为一个宏工作执行console.log('script start'),输入script start;
执行setTimeout,是一个异步动作,放入宏工作异步队列中;
执行async1(),输入async1 start,持续向下执行;
执行async2(),输入async2,并返回了一个promise对象,await让出了线程,把返回的promise退出了微工作异步队列,所以async1()上面的代码也要期待下面实现后继续执行;
执行 new Promise,输入promise1,而后将resolve()放入微工作异步队列;
执行console.log('script end'),输入script end;
到此同步的代码就都执行实现了,而后去微工作异步队列里去获取工作
接下来执行resolve(async2返回的promise返回的),输入了async1 end;
而后执行resolve(new Promise的),输入了promise2;
最初执行setTimeout,输入了settimeout。
在第4步中, await 这里有一个机制, 就是 await 的期待, 不会阻塞内部函数的执行, 而 await 期待的 如果是一个 Promise 则 Promise 外面的代码还是同步执行, 如果不是 Promise ,就会应用 Promise.resolve 来进行封装, 这里的 async2 是一个 async 办法, 外面的 打印会同步执行, 而 await async2() 前面的代码 会放到微工作队列中的第一个地位,期待内部同步代码执行结束当前再执行。
所以我晓得了script end为什么会优先于async1 end输入。
更多分享:开发者网站