插入法分析promise和await面试题以及宏任务和微任务的区别

本文主要是分析promise函数和setTimeout函数,以及通过执行的顺序帮助我们了解宏任务(macrotask )和微任务(microtask ),所以一定要看到最后,看完记得自己多练习,否则还是不能理解。

Promise 是一个 ECMAScript 6 提供的类,目的是更加优雅地书写复杂的异步任务。他可以帮助我们将多个异步的嵌套执行在代码上写成同步的格式。

async函数是generate函数的语法糖:generate函数的*号换成async修饰。

await函数相对应的就是yield函数。

下面看几道例题:

首先是先掌握promise内部的执行顺序:

new Promise(function(resolve){

    console.log('promise1');

    resolve('resolved1');

}).then(function(data){

    console.log(data);});
        
    new Promise(function(resolve){

    console.log('promise2');

    resolve('resolved2');

}).then(function(data){

    console.log(data);
    });
console.log("console 3");

执行顺序是promise1,promise2,console 3, resolved1, resolved2。

一些同步代码会比promise.then后面的先执行,而promise.then之前的第一个(resolve, reject)=> {}回调函数是同步代码,如定义10个promise,则他们的第一个回调函数和打印函数一起,直接放在主线程调用栈里,因为他们全部都是同步的,而promise.then后面的回调函数,放在微任务队列里等待执行,他们的顺序在不同浏览器可能不完全按照代码的顺序执行,即使是console.log()

再看下一道题:

async function func1(){
    console.log('func1');

    var a = await func2(); //当await返回非promise

    console.log('func1 return');
}

function func2(){

    console.log('func2');

} //返回undefined

func1();

new Promise(function(resolve){

    console.log('promise1');

    resolve('resolved');

}).then(function(data){

    console.log(data);

});

执行结果:

func1
func2
promise1
func1 return
resolved

func1 func2 promise1他们是同步的,执行完以后再去执行promise后面的内容。async函数只会卡住当前函数内容的语句,不会阻塞后面的函数,遇到await函数会先返回,执行async函数后面代码。await func2()可以看做是func2.then(res => console.log("func1 return"));。

下面分析一道头条笔试题:

在面试的时候,可以使用插入法分析问题,在确定代码顺序为ABCD的执行顺序时,先比较AB结果,例如执行结果是BA。然后插入C,例如C在最后,那么ABC的执行顺序是BAC,最后插入D,如D在AC之间,那么最后的执行顺序就是BADC。

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');  

按照执行的顺序,script start是同步代码,并且又在最前面执行,然后async 1 start,async2,async 1 end是一个顺序,async 1 start,async2是同步的,async 1 end是异步的放在微任务里,这样我们可以先确定这四个执行顺序:

script start, async 1 start, async2, async 1 end

然后是promise1,按照第一道例题的思路,他应该直接作为同步代码执行,放在async2后面,注意不是 async 1 start后面:

script start, async 1 start, async2,promise1, async 1 end

然后promise2放在async 1 end后面,他们都是promise的回调:

script start, async 1 start, async2,promise1, async 1 end,promise2

然后是script end,它应该是放在所有微任务之前、主进程调用栈的最后一个,所以在promise1后面:

script start, async 1 start, async2,promise1,script end, async 1 end,promise2

上面的结果中,script start,async 1 start, async2,promise1,script end属于第一轮宏任务即(script上下文),然后执行第一轮微任务async 1 end,promise2。

最后还剩下一个setTimeout函数,他属于宏任务(浏览器环境,非node环境),即第二个宏任务,当第一轮微任务全部执行完,开始执行第二轮宏任务,所以最后的执行顺序是:

script start, async 1 start, async2,promise1,script end, async 1 end,promise2,setTimeout。

浏览器环境下宏任务和微任务的执行如下:

在这里插入图片描述

 script上下文作为第一个宏任务,一定是最先执行的,那些打印和同步的代码都在第一个宏任务里。

1、js宏任务有:<script>整体代码、setTimeout、setInterval、setImmediate、Ajax、DOM事件

2、js微任务有:process.nextTick、MutationObserver、Promise.then catch finally

每次执行当前的一个宏任务,执行过程中遇到微任务放到微任务队列。当前的宏任务执行完,回去检查有没有微任务。执行完以后再去执行下一个宏任务,所以头条的这道面试题,执行了三个任务:第一个script宏任务——>第一个微任务——>第二个setTimeout宏任务

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值