promise中的回调函数、async和await的执行顺序

一、几个关键问题:

1、宏队列:用来保存待执行的宏任务(回调),比如:定时器回调、DOM事件回调、ajax回调。

2、微队列:用来保存待执行的微任务(回调),比如:promise的回调、MutationObserver的回调。

3、JS执行时,必须先执行所有的同步任务代码,然后将微队列中的任务取出执行,当所有微任务执行完成以后,再取出宏队列中的代码执行。所以执行顺序是:同步任务---->微队列任务---->宏队列任务。

4、Promise((resolve, reject) => { resolve(1) }).then(()=>{console.log(1)})中(resolve, reject) => {}是同步执行的,.then()也是同步执行,但是.then()中的回调函数是异步执行。

5、类似与.then(()=>{console.log(1)}).then(()=>{console.log(2)})这样的结构,第一个.then中有return之后,第二个.then中的函数才会执行。(如果.then()中没有人为指定return,系统会默认return undefined)。

6、await右侧的表达式一般为promise对象但也可以是其他值,如果是promise对象,await返回promise成功值,如果表达式是其他值,则直接将此值作为await的返回值。

7、await必须写在async函数中,但async函数中可以没有await

二、几道考执行顺序的题

1、给出以下代码的执行结果 

setTimeout(() => {
    console.log("0")
}, 0)
new Promise((resolve, reject) => {
    console.log("1")
    resolve()
}).then(() => {
    console.log("2")
    new Promise((resolve, reject) => {
      console.log("3")
      resolve()
    }).then(() => {
      console.log("4")
    }).then(() => {
      console.log("5")
    })
}).then(() => {
   console.log("6")
})
new Promise((resolve, reject) => {
    console.log("7")
    resolve()
}).then(() => {
    console.log("8")
})

答案: 1,7,2,3,8,4,6,5,0 

解析:

(1)按顺序往下看,定时器先执行console.log("0")进入宏队列等待。//此时输出:[ ],微队列:[ ],宏队列:[0]

(2)与promise同步执行的(resolve, reject) => {},输出1,resolve执行完执行.then,then中为回调函数进入微队列等待。//此时输出:[1],微队列:[2],宏队列:[0]

(3)第三个promise执行,同步执行(resolve, reject) => {},输出7,resolve执行完执行.then,then中为回调函数,故console.log(8)进入微队列进行等待。//此时输出:[1,7],微队列:[2,8],宏队列:[0]

(4)此时最外层已经没有需要同步执行的代码了,所以执行微队列中的第一个回调函数,输出2并执行new promise。//此时输出:[1,7,2],微队列:[8],宏队列:[0]

(5)new promise中的(resolve, reject) => {}同步执行,输出3执行resolve(),并且后面的所有.then也同步执行,但需注意.then是同步执行是因为promise().then().then()是同一级的。但是.then()中的回调函数需等到上一级的函数或.then有返return了才开始执行。所以此时console.log(4)进入微队列。new promise()执行完成故上一层.then()执行完成return undefined 。故与它相连的.then()中的回调函数执行 console.log(6) 进入微队列。     //此时输出:[1,7,2,3],微队列:[8,4,6],宏队列:[0]

(6)此时该层已经没有需要同步执行的代码了,微队列执行打印8,然后执行打印4。//此时输出:[1,7,2,3,8,4],微队列:[6],宏队列:[0]。

(7)console.log(4)执行完成后,与它同一级的.then()得到返回值,其中的回调函数开始执行console.log(5)进入微队列。//此时输出:[1,7,2,3,8,4],微队列:[6,5],宏队列:[0]。

(8)此时该层已经没有需要同步执行的代码了,微队列执行,打印6,打印5,微队列执行完毕。//此时输出:[1,7,2,3,8,4,6,5],微队列:[ ],宏队列:[0]。

(9)所有微队列执行完毕,执行宏队列,打印5。//此时输出:[1,7,2,3,8,4,6,5,0],微队列:[ ],宏队列:[]。

2、给出以下代码的执行结果

async function async1() {
    console.log('1');
    await async2();
    console.log('2');
}
 
async function async2() {
    console.log('3');
}
 
console.log('4');
 
setTimeout(()=>{
    console.log('5');
},0)
 
async1();
 
new Promise((resolve)=>{
    console.log('6');
    resolve();
}).then(()=>{
    console.log('7');
});
 
console.log('8');

答案:4 、1、3、6、8、2、7、5

解析:

(1)按顺序执行,先执行同步代码console.log(4)    //输出:[4],微队列:[ ],宏队列:[ ]

(2)setTimeout执行,进入宏队列。   //输出:[4],微队列:[ ],宏队列:[5]

(3)执行async1,同步执行sonsole.log(1),执行async2,console.log(2)进入微队列等待,async2同步执行console.log(3)。//输出:[4,1,3],微队列:[2],宏队列:[5]。

(4)下一个new promise中的(resolve, reject) => {}同步执行打印6,执行resolve以及.then()中的回调函数,console.log(7)进入微队列等待。    //输出:[4,1,3,6],微队列:[2,7],宏队列:[5]

(5)顺序执行同步代码console.log(8)。 //输出:[4,1,3,6,8],微队列:[2,7],宏队列:[5]。

(6)此时最外层的同步代码均已执行完毕,执行微队列,打印2,7,微队列执行完毕,执行宏队列打印5。   //输出:[4,1,3,6,2,7,5],微队列:[ ],宏队列:[ ]

3、给出以下代码的执行结果

(async function () {
    await console.log(1);
    console.log(2);
})().then(
    () => console.log(1)
);
console.log(4);
setTimeout(function () {
    console.log(5);
}, 0)

答案:1,4,2,1,5

知识点:

(1)(function fun(a,b,c){})(1,2,3) 小括号中的函数会被解析成表达式,1,2,3会被解析为函数的实参

(2)async和await。

(3)微队列和宏队列。

解析:

(1)await后面的console.log(1)先执行,console.log(2)进入微队列等待。 //[1]

(2)执行同步任务console.log(4)。 //[1,4]

(3)console.log(5)进入宏队列等待。//[1,4]

(4)同步任务以全部执行完,console.log(2)出微队列执行,async function(){}全部执行完毕.then中的1进入微队列等待。//[1,4,2]

(5)由于没有其他同步任务和微队列要执行,所以从微队列中取出1。 //[1,4,2,1]

(6)所有微队列都执行完毕,从宏队列中取出5。 //[1,4,2,1,5]

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Promise是一种用于处理异步操作的特殊对象。它表示一个尚未完成但最终会完成的操作,并可以用于处理回调地狱和编写更清晰、更可读的异步代码。一个Promise对象有三种状态:pending(进行)、fulfilled(已成功)和rejected(已失败)。一旦Promise的状态变为fulfilled或rejected,它就被认为是已解决(settled)。 创建Promise对象时,我们可以通过传递一个执行器函数来定义异步操作。执行器函数接受两个参数:resolve和reject。当异步操作成功时,我们可以调用resolve函数将Promise的状态设置为fulfilled,并传递解决值。当异步操作失败时,我们可以调用reject函数将Promise的状态设置为rejected,并传递错误信息。 下面是一个使用Promise的简单示例: ```javascript const myPromise = new Promise((resolve, reject) => { // 异步操作 setTimeout(() => { const randomNumber = Math.random(); if (randomNumber > 0.5) { resolve(randomNumber); } else { reject('Number is less than 0.5'); } }, 1000); }); // 使用then()方法处理Promise的解决结果 myPromise.then((result) => { console.log('Resolved:', result); }).catch((error) => { console.log('Rejected:', error); }); ``` 上面的代码创建了一个Promise对象,其包含一个延迟1秒的异步操作。如果生成的随机数大于0.5,则调用resolve函数解决Promise,否则调用reject函数拒绝Promise。然后,我们使用then()方法处理Promise的解决结果,catch()方法处理Promise的拒绝结果。 在ES2017,引入了async/await关键字,它们是使用Promise的语法糖,可以更简洁地处理异步操作。 async函数是一个返回Promise的函数,它使用async关键字声明。在async函数,我们可以使用await关键字来等待一个Promise解决,并返回解决值。使用async/await可以将异步代码写成类似于同步代码的形式,使其更易读和理解。 下面是一个使用async/await的示例: ```javascript function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } async function myAsyncFunction() { try { console.log('Start'); await delay(1000); console.log('After 1 second'); await delay(2000); console.log('After 2 seconds'); } catch (error) { console.log('Error:', error); } } myAsyncFunction(); ``` 上面的代码定义了一个async函数`myAsyncFunction()`,其使用了await关键字等待两个延迟操作的Promise解决。通过使用try-catch块,我们可以捕获可能出现的错误。 当我们调用`myAsyncFunction()`时,它会被执行,并按顺序打印出"Start"、"After 1 second"和"After 2 seconds"。由于async函数返回一个Promise,我们也可以使用then()和catch()方法来处理解决和拒绝结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值