news 2026/6/15 9:16:03

Promise、async / await 详解!!!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Promise、async / await 详解!!!

一、Promise 基础

1. 出现背景

JS 传统异步:回调函数,多层嵌套会形成回调地狱,代码嵌套层级深、可读性极差、难以统一错误处理。
Promise 是 ES6 原生异步解决方案,用链式调用扁平化异步代码。

2. Promise 三种状态(不可逆)

  1. pending等待中(初始)
  2. fulfilled成功(resolved)
  3. rejected失败

状态一旦从 pending 变为成功/失败,就永久凝固,无法再次修改。

3. 基础语法

// 构造函数接收 executor 执行器,同步立即执行constp=newPromise((resolve,reject)=>{// 异步操作:定时器、接口请求、文件读写setTimeout(()=>{constres=Math.random();if(res>0.5){resolve("请求成功数据");// 触发 .then}else{reject("请求失败");// 触发 .catch}},1000);});

4. 实例方法

(1).then(onFulfilled, onRejected)

接收成功回调,返回新 Promise,支持链式调用

p.then(data=>{console.log(data);return"下一次then数据";}).then(nextData=>{console.log(nextData);});
(2).catch()

捕获失败+ 链式代码内部抛出的异常,统一错误处理

p.then(data=>console.log(data)).catch(err=>console.error("异常:",err));
(3).finally()

无论成功失败都会执行,不接收参数,常用于loading关闭、销毁操作

p.then(...).catch(...).finally(()=>{console.log("异步执行完毕");});

5. Promise 静态方法(批量异步常用)

方法作用结束条件
Promise.all([p1,p2,p3])所有Promise并行执行全部成功才resolve;任意一个失败立刻reject
Promise.race([p1,p2])竞速第一个敲定状态(成功/失败)就结束
Promise.allSettled()等待全部执行完毕不管成功失败,收集所有结果数组
Promise.any()任一成功即可第一个成功resolve;全部失败才reject

示例:

constp1=Promise.resolve(1);constp2=Promise.resolve(2);Promise.all([p1,p2]).then(arr=>console.log(arr));// [1,2]

二、async / await

ES2017

1. 本质

语法糖,基于 Promise 封装,彻底把异步代码写成同步写法,不再链式.then

2. 语法规则

  1. async修饰函数:函数永远返回 Promise 对象
    • return 普通值 → 自动包装为Promise.resolve(值)
    • throw 错误 → 自动包装为Promise.reject(错误)
  2. await只能写在 async 函数内部,不能单独全局使用;
    等待 Promise 敲定状态,取出 resolve 的结果,阻塞当前代码往下执行(不阻塞主线程)。

3. 基础示例

// 封装一个Promise请求functionrequestData(){returnnewPromise((resolve)=>{setTimeout(()=>resolve("后端接口数据"),1000);});}// async + awaitasyncfunctiongetData(){console.log("开始请求");constresult=awaitrequestData();// 等待异步结束,拿到结果console.log(result);// 1秒后打印:后端接口数据returnresult;}// async函数调用依旧要用.then或再次awaitgetData().then(res=>console.log(res));

4. 错误捕获(关键)

await遇到 reject 会直接抛出异常,必须用try/catch捕获:

asyncfunctionsafeReq(){try{constres=awaitPromise.reject("接口500");console.log(res);}catch(err){console.error("捕获异常:",err);}finally{console.log("执行收尾");}}safeReq();

三、链式异步对比(回调地狱 → Promise → async/await)

1. 回调地狱

setTimeout(()=>{console.log(1);setTimeout(()=>{console.log(2);setTimeout(()=>console.log(3),1000);},1000);},1000);

2. Promise 链式

newPromise(resolve=>setTimeout(()=>resolve(1),1000)).then(v=>{console.log(v);returnnewPromise(r=>setTimeout(()=>r(2),1000))}).then(v=>{console.log(v);returnnewPromise(r=>setTimeout(()=>r(3),1000))})

3. async/await(最优雅)

functiondelay(num){returnnewPromise(resolve=>setTimeout(()=>resolve(num),1000));}asyncfunctionrun(){constn1=awaitdelay(1);console.log(n1);constn2=awaitdelay(2);console.log(n2);constn3=awaitdelay(3);console.log(n3);}run();

四、常用实操要点

1. 并行 await(不要串行浪费时间)

多个无依赖接口,不要挨个 await,改用Promise.all并发:

// 串行:总耗时≈2sasyncfunctionserial(){awaitdelay(1000);awaitdelay(1000);}// 并行:总耗时≈1sasyncfunctionparallel(){constp1=delay(1000);constp2=delay(1000);awaitPromise.all([p1,p2]);}

2. async 函数返回值细节

asyncfunctionfn(){return100;}console.log(fn());// Promise { 100 }fn().then(v=>console.log(v));// 100

3. 顶层 await

ES模块中可用

.mjs模块化文件里,不用包裹 async 函数,直接写:

constdata=awaitfetch("/api/list");

五、三者关系总结

  1. Promise 是底层异步标准,解决回调嵌套;
  2. async/await 是 Promise 的语法糖,只是写法优化,不能替代Promise
  3. 实际开发组合用法:接口函数封装返回 Promise,业务代码用async await + try/catch编写;
  4. 所有.then链式场景,都可以等价改写为 await 同步风格代码。

六、经典面试高频题

  1. await后面跟非Promise会发生什么?
    自动包装为Promise.resolve(值),立即执行。
await123;// 等价 await Promise.resolve(123)
  1. async函数内部await阻塞,会不会卡住浏览器?
    不会。只是当前async函数内后续代码暂停执行,JS主线程继续执行其他同步代码,异步入事件队列,不会阻塞页面渲染。

  2. try/catch能捕获.then里手动throw的错误吗?
    不能,只能捕获当前await抛出的reject异常;.then内部错误只能用自身.catch

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!