JavaScript 异步编程入门:Promise 与 async/await
在 JavaScript 里,很多操作不会立刻完成,比如请求接口、读取文件、定时等待。如果用同步方式写,页面会被卡住;异步编程就是为了解决这个问题。本文介绍 Promise 与 async/await 的基本用法和常见坑。
一、Promise 是什么
Promise 表示一个未来才会完成的操作,它有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。状态一旦改变就不会再变。
function getUser() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve({ name: '小明' }), 1000);
});
}
getUser().then(user => console.log(user.name)).catch(err => console.error(err));
then 接收成功的结果,catch 统一处理失败。多个异步操作可以链式调用:上一个 then 返回的值会传给下一个 then;返回新的 Promise 时,链会等待它完成后再继续。
二、async/await 让异步代码像同步一样写
async 声明的函数总会返回一个 Promise,return 的值就是成功的结果,抛出的错误就是失败的原因。await 只能在 async 函数里使用,它会等待 Promise 完成再继续执行,并把结果取出来。
async function main() {
try {
const user = await getUser();
console.log(user.name);
} catch (err) {
console.error('加载失败', err);
}
}
这样的写法把嵌套的回调拍平成了从上到下的顺序,读起来像同步代码,但它并不会阻塞主线程。
三、常见坑
第一,忘记写 await。调用 async 函数却不 await,拿到的是 Promise 而不是数据,后续取值会得到 undefined。第二,在 async 函数里漏掉 try/catch,错误会变成未处理的 rejected Promise,排查起来很费力。第三,本来可以并行却写成了串行,两个独立请求依次 await 会白白多等一倍时间,可以用 Promise.all 一起发起。第四,在 forEach 里用 await 不会按顺序等待,因为 forEach 不会等待回调里的 Promise,需要顺序执行时改用 for…of 循环。第五,以为 await 能暂停整个程序,其实它只暂停当前 async 函数,主线程照常运行。
四、结语
Promise 负责描述异步结果,async/await 负责用同步的写法组织异步流程。掌握它们之后,再遇到接口请求、定时任务和链式处理,就可以写出既清晰又不容易出错的代码。建议动手写几个小例子:先请求数据再渲染列表,再试着并行请求两个接口,对比串行与并行的耗时,坑自然就记住了。
- 点赞
- 收藏
- 关注作者
评论(0)