async/await与Promise结合时的执行顺序是怎样的?

执行顺序遵循以下核心规则:

同步代码 > 微任务(Promise、await后代码)>宏任务(如setTimeout)

**async/await与Promise的含义: **Promise:用于替代传统的回调地狱 Promise是一个对象,表示异步操作的最终完成(或失败)及其结果值。它有三种状态:

  • pending:初始状态,既不是成功也不是失败。
  • fulfilled:操作成功完成。
  • rejected:操作失败。

一旦状态变为 fulfilled 或 rejected,就称为 resolved(已解决),且状态不可再变。

只能从pending变成fulfilled 或者rejected状态,不能变成pending

js 复制代码
new Promise((resolve, reject) => {
    if (success) {
      resolve("操作成功"); // 成功时调用 resolve
    } else {
      reject(new Error("操作失败")); // 失败时调用 reject
    }
});

链式调用:then ()、catch ()、finally ()

Promise 通过 .then().catch() 处理结果,支持链式调用

catch()可以监听前面任一过程的错误

js 复制代码
promise.then((value) => {
  console.log(value); // 输出:操作成功
}).catch((error) => {
  console.error(error); // 操作失败时执行
}) .finally(() => 
  console.log("无论如何都会执行")
);

链式调用的返回值

.then() 和 .catch() 会返回一个新的 Promise,因此可以链式调用。

如果返回值是普通值(非 Promise),则会被包装为 Promise.resolve(返回值)。

如果返回值是 Promise,则会等待该 Promise 解决,并将其结果传递给下一个 .then()。

js 复制代码
promise
  .then((value) => {
    return value + "!"; // 返回普通值
  })
  .then((newValue) => {
    return new Promise((resolve) => {
      setTimeout(() => resolve(newValue + " again"), 1000); // 返回 Promise
    });
  })
  .then((finalValue) => console.log(finalValue)); // 输出:操作成功! again

除此之外还有:Promise.all ()、Promise.race ()、Promise.allSettled()、Promise.any() Promise.all ():并行执行多个 Promise,返回一个新的 Promise,当所有 Promise 都成功时才成功,否则失败。

Promise.race (): 并行执行多个 Promise,返回一个新的 Promise,第一个解决(无论成功或失败)的 Promise 的结果就是最终结果

js 复制代码
const fastPromise = new Promise((resolve) => setTimeout(() => resolve("快的 Promise"), 500));
const slowPromise = new Promise((resolve) => setTimeout(() => resolve("慢的 Promise"), 2000));
 
Promise.race([fastPromise, slowPromise])
  .then((value) => console.log(value)) // 输出:快的 Promise
  .catch((error) => console.error(error));

Promise.allSettled(): 返回一个 Promise,当所有输入的 Promise 都已解决(无论成功或失败)时,返回包含每个 Promise 结果的数组。

js 复制代码
Promise.allSettled([promise1, promise2])
  .then((results) => {
    results.forEach((result) => {
      if (result.status === "fulfilled") {
        console.log("成功:", result.value);
      } else {
        console.log("失败:", result.reason);
      }
    });
  });

Promise.any(): 返回一个 Promise,只要有一个输入的 Promise 成功,就返回该 Promise 的结果;只有当所有 Promise 都失败时才失败。

js 复制代码
Promise.any([promise1, promise2])
  .then((value) => console.log("至少有一个成功:", value))
  .catch((error) => console.error("所有都失败:", error));

async 函数

async/await 是 ES2017(ES8)引入的语法糖,用于简化 Promise 的使用,让异步代码看起来更像传统的同步代码。它基于 Promise 实现,本质上是 Promise 的语法增强。

定义:使用 async 关键字声明的函数,自动返回一个 Promise对象,表示函数内部有异步操作。 返回值:函数内部的返回值会被包装为 Promise.resolve(返回值)。

js 复制代码
async function fn1() {
    return 123
}
function fn2() {
    return 123
}
console.log("fn1",fn1())
/*输出结果:
 fn1  Promise {<fulfilled>: 123}
[[Prototype]]:Promise
[[PromiseState]]:"fulfilled"
[[PromiseResult]]: 123
 */
console.log("fn2",fn2())
/*输出结果:
 fn2   123
 */

await 表达式

  • 作用 :暂停 async 函数的执行,等待 Promise 解决(resolved),并返回其结果。
  • 语法限制 :只能在 async 函数内部使用。

await等的是右侧「表达式」的结果,执行顺序从右--》左

也就是说await同行后面的的代码一旦完成就把后续代码放进微队列,后面没有代码了那么对应的async进入微队列

await等待有两种结果:

  • 如果await后面是不是promise对象,那么await会阻塞后面的代码,先执行async函数外面的同步代码,同步代码执行完毕,再回到async内部,把这个非promise的东西,作为await表达式的结果。
  • 如果await后面是promise对象,那么他会在async外部的同步代码执行完毕之后等到promise对象fulfilled,然后把resolve的参数作为await表达式的运行结果。

例题理解:

小提示:Promise.resolve()是同步执行的方法,后面可以跟一个值或者函数,会立即返回一个已解决的状态(resolved)

await 42 或函数;类似于Promise.resolve(42或函数) 是立即执行的

Promise.resolve().then就是微任务

(1)这个例子只是我个人读代码顺序

js 复制代码
async function asy1() {
    console.log("asy1 start")
    await asy2()
    console.log("asy1  end")
}
 
const asy2 = async ()=>{
    console.log("asy2 start")
    //setTimeout(函数,时间)在多少时间后,把函数内容放到宏队列
    await setTimeout(()=>{
        Promise.resolve().then(()=>{
             console.log("asy2 setTimeout Promise.resolve().then")
        })
        console.log("asy2 setTimeout")
    },10)
    console.log("asy2  end")
}
 
const asy3 = async ()=>{
    console.log("asy3 start")
    Promise.resolve().then(()=>{
        console.log("asy3 Promise.resolve().then")
    })
    console.log("asy3  end")
}
 
asy1();
console.log("script")
asy3();

代码梳理:从上往下读,声明了三个函数,调用函数asy1、打印语句、调用函数asy2;

此时的同步函数(从上到下依次执行):

asy1();

console.log("script")

asy3();

开始执行,进入asy1函数

js 复制代码
async function asy1() {
    console.log("asy1 start")     //同步代码
    await asy2()                         //同步代码
    console.log("asy1  end")
}

控制台输出:asy1 start

进入asy2函数

js 复制代码
const asy2 = async ()=>{
    console.log("asy2 start")   //同步代码
    //setTimeout(函数,时间)在多少时间后,把函数内容放到宏队列
    await setTimeout(()=>{              //同步代码
        Promise.resolve().then(()=>{
             console.log("asy2 setTimeout Promise.resolve().then")
        })
        console.log("asy2 setTimeout")
    },10)
    console.log("asy2  end")        //同步代码
}

控制台输出:asy2 start

等待执行的任务:

宏队列:setTimeout【10ms后执行】

微队列:等待asy2完成 此时asy2还在等待,asy1暂时执行完毕开始执行console.log("script")

控制台输出:script 打印语句执行完毕,开始调用asy3

js 复制代码
const asy3 = async ()=>{
    console.log("asy3 start")          //同步代码
    Promise.resolve().then(()=>{                               
        console.log("asy3 Promise.resolve().then")    
    })       //放入微队列,稍后异步执行                     
    console.log("asy3  end")          //同步代码
}

控制台输出:asy3 start asy3 end

等待执行的任务: 宏队列:setTimeout【10后执行】 微队列: ①等待asy2完成执行console.log("asy2 end") ②asy3的Promise.resolve().then

此时第一层的同步代码执行完毕,接下来先清空微队列,asy2完成后,输出打印结果asy1的打印语句进入微队列等待执行

控制台输出:asy2 end

等待执行的任务: 宏队列:setTimeout【10后执行】 微队列: ①asy3的Promise.resolve().then ②console.log("asy1 end")

依次执行微队列,控制台输出:

asy3 Promise.resolve().then

asy1 end

微队列执行完毕,开始执行宏队列,也就是执行asy2 的这段代码,此时Promise.resolve().then和打印语句都是同步代码,Promise里面的打印语句进入微队列

js 复制代码
 await setTimeout(()=>{
        Promise.resolve().then(()=>{
             console.log("asy2 setTimeout Promise.resolve().then")
        })
        console.log("asy2 setTimeout")
    },10)

此时控制台打印: asy2 setTimeout

等待执行的任务: 微队列:console.log("asy2 setTimeout Promise.resolve().then")

执行最后一个微队列,控制台输出:

asy2 setTimeout Promise.resolve().then

最终控制台的输出结果:

(2)首先分析代码中的同步、宏任务、微任务

js 复制代码
console.log("----------------   start");//同步代码
async function async1() {
    console.log("async1 start");//同步代码
    await async2();//同步代码
    console.log("async1  end");//微任务
}
 
async function async2() {
    console.log("async2 -----");//同步代码
}
 
async1();//同步代码
 
setTimeout(function(){
    console.log("setTimeout");
},0);//宏任务
 
new Promise((resolve)=>{
    console.log("Peomise");//同步代码
    resolve();
})
    .then(function(){
        console.log("Peomise.then");//微任务
    })
    .then(function(){
        console.log("Peomise.then.then");//微任务
    });
console.log("----------------   end");//同步代码
 

从上往下读取代码,先执行同步代码

此时控制台输出:---------------- start

往下读是两个函数,然后是调用async1();开始执行async1的代码

js 复制代码
async function async1() {
    console.log("async1 start");//同步代码
    await async2();//同步代码
    console.log("async1  end");//微任务
}

此时控制台输出:async1 start

等待async2执行,打印语句进入微任务

微任务:async1的console.log("async1 end");

js 复制代码
async function async2() {
    console.log("async2 -----");//同步代码
}

此时控制台输出:async2 -----

async1的调用暂时执行完毕,接下来是setTimeout是宏任务,在往下读立即执行Promise的同步代码,其中.then是微任务进入任务队列

宏任务:setTimeout(function() 微任务:①async1的console.log("async1 end"); ②Promise.then ③Promise.then.then

此时控制台输出:Peomise

然后执行最后一行代码console.log("---------------- end");//同步代码

此时控制台输出:---------------- end

同步代码执行完毕

接下来执行微任务

此时控制台输出:async1 end Promise.then Promise.then.then

微任务执行完毕,开始宏任务:

此时控制台输出:setTimeout

最终输出结果:

相关推荐
霸王蟹12 小时前
从前端工程化角度解析 Vite 打包策略:为何选择 Rollup 而非 esbuild。
前端·笔记·学习·react.js·vue·rollup·vite
EndingCoder12 小时前
React从基础入门到高级实战:React 生态与工具 - 构建与部署
前端·javascript·react.js·前端框架·ecmascript
市民中心的蟋蟀12 小时前
第十章 案例 4 - React Tracked 【上】
前端·javascript·react.js
工呈士12 小时前
React Hooks 与异步数据管理
前端·react.js·面试
NoneCoder16 小时前
React 路由管理与动态路由配置实战
前端·react.js·面试·前端框架
海盐泡泡龟16 小时前
React和原生事件的区别
前端·react.js·前端框架
飘尘16 小时前
用GSAP实现一个有趣的加载页!
前端·javascript·react.js
TE-茶叶蛋1 天前
React-props
前端·javascript·react.js
安分小尧1 天前
[特殊字符] 超强 Web React版 PDF 阅读器!支持分页、缩放、旋转、全屏、懒加载、缩略图!
前端·javascript·react.js
EndingCoder1 天前
React从基础入门到高级实战:React 高级主题 - React Concurrent 特性:深入探索与实践指南
前端·javascript·react.js·前端框架