📅  最后修改于: 2023-12-03 15:13:32.685000             🧑  作者: Mango
JavaScript 作为一种单线程编程语言,经常需要进行异步编程。在很长一段时间里,回调函数是最常见的异步编程方式。但是回调函数会导致代码严重嵌套,通常被称为“回调地狱”。
随着 JavaScript 对异步编程的理解和使用的深入,Promise 和 async/await 成为了更好的异步编程方案。下面我们将详细介绍这两种方案。
Promise
是一个表示一个异步操作的结果的对象。Promise 对象可以有三种状态:
一个 Promise 对象由 Promise 构造函数创建,构造函数接收一个函数(称为控制函数)作为参数,控制函数又接收两个函数,分别表示 Promise 成功和失败时的回调函数。下面是一个简单的 Promise 示例:
const promise = new Promise((resolve, reject) => {
if (Math.random() > 0.5) {
resolve('hello, world');
} else {
reject(new Error('something wrong'));
}
});
promise.then(
(value) => {
console.log(value);
},
(error) => {
console.error(error);
}
);
在上面的示例中,Promise 的控制函数中,我们使用 Math.random() 生成一个随机数,如果随机数大于 0.5,我们就将 Promise 状态设为 resolved,值为字符串 'hello, world';否则,我们就将 Promise 状态设为 rejected,值为一个错误对象。不管 Promise 最终状态是 resolved 还是 rejected,我们都将其结果进行了打印输出。
async/await
是 ECMAScript 2017 引入的特性,可以使异步代码看起来像同步代码。async/await 是基于 Promise 实现的语法糖。
与 Promise 不同,使用 async/await 不需要链式调用 then 函数。只需要使用 async 关键字定义一个异步函数,然后在需要异步处理的代码块中使用 await 关键字就可以了。
async/await 的一个优点是可以在函数内捕获异步错误。如果使用 Promise,需要手动调用 reject 函数来传递异常,然后在 catch 函数中捕获异常。而使用 async/await,异常会自动被捕获,并且可以直接在 try...catch 语句中处理。
下面是一个使用 async/await 实现异步操作的示例:
function timeout(duration) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, duration);
});
}
async function task() {
console.log('task start');
await timeout(1000);
console.log('task end');
}
task();
在上面的示例中,我们定义了一个异步函数 task,内部使用了 await 关键字等待一个异步操作 timeout 执行完毕。注意,异步函数内部使用 await 关键字会自动将其后的表达式封装为 Promise 对象,这个 Promise 对象会在表达式求值完成后立即 resolve。
Promise.all
方法可以将多个 Promise 对象包装成一个新的 Promise 实例。
Promise.all 接收一个数组作为参数,数组中的每一个元素都是一个 Promise 对象。当数组里的所有元素都变成 resolve 状态时,Promise.all 返回的 Promise 对象就会变成 resolve 状态,将所有 Promise 实例返回的数组作为结果传递给回调函数。如果数组里有任何一个元素是 reject 状态,那么 Promise.all 返回的 Promise 对象就直接变成 reject 状态,并传递第一个被 reject 状态的元素。
下面是一个使用 Promise.all 的示例:
const p1 = new Promise((resolve) => setTimeout(() => resolve('p1'), 3000));
const p2 = new Promise((resolve) => setTimeout(() => resolve('p2'), 2000));
const p3 = new Promise((resolve, reject) => setTimeout(() => reject(new Error('p3')), 1000));
Promise.all([p1, p2, p3])
.then((values) => console.log(values))
.catch((error) => console.error(error));
在上面的示例中,我们创建了三个 Promise 对象 p1、p2、p3,分别在 3s、2s 和 1s 后 resolve 或 reject。 最后使用 Promise.all 把这三个 Promise 对象组合在一起。由于 p3 比 p1、p2 更快 resolve,它成为了 Promise.all 返回的 Promise 对象最终值被 reject 的对象,最后的结果就是一个 Error 对象。
通过以上介绍,我们可以看到:
以上就是本文对 async/await 和 Promise.all 的详细介绍,希望对你实际开发中的异步编程有所帮助。