Promises 是 ECMAScript 2015 中引入的一种异步编程模式,它可以方便地处理异步操作的结果,以及避免回调嵌套的问题。在 ECMAScript 2020 中,Promises 得到了一些优化和扩展,使得它们更加灵活和易用。
优化和扩展
可处理的错误
在早期的 Promises 实现中,错误处理往往是比较麻烦的。通常需要在 Promise 的链式调用中使用 .catch() 方法来捕获错误,或者使用 try-catch 语句来处理。但是这样的做法往往会导致代码冗长和不易维护。
在 ECMAScript 2020 中,Promises 的错误处理得到了改进。现在,Promise 的构造函数可以接受一个可选的 onRejected 参数,用于处理 Promise 被拒绝时的错误。例如:
// www.javascriptcn.com code example
const promise = new Promise((resolve, reject) => {
// some asynchronous operation
if (/* operation succeeds */) {
resolve(result);
} else {
reject(new Error('operation failed'));
}
}).catch(error => {
console.error(error);
});在上面的例子中,我们在 Promise 的构造函数中传入了一个 reject 函数,用于处理 Promise 被拒绝时的错误。如果 Promise 被拒绝,就会调用传入的 onRejected 函数,并将错误作为参数传递给它。这样就可以避免在 Promise 链式调用中使用 .catch() 方法来捕获错误。
新的静态方法
在 ECMAScript 2020 中,Promise 类新增了一些静态方法,使得 Promises 更加灵活和易用。
Promise.allSettled()
Promise.allSettled() 方法接受一个 Promise 数组作为参数,并返回一个新的 Promise,该 Promise 在所有 Promise 都完成后解决。与 Promise.all() 方法不同的是,即使其中有 Promise 被拒绝,Promise.allSettled() 也会在所有 Promise 完成后解决,并返回一个数组,数组中包含每个 Promise 的状态和结果。例如:
// www.javascriptcn.com code example
const promises = [
Promise.resolve('success'),
Promise.reject(new Error('failure')),
Promise.resolve('another success')
];
Promise.allSettled(promises).then(results => {
console.log(results);
// Output:
// [
// { status: 'fulfilled', value: 'success' },
// { status: 'rejected', reason: Error: failure at <anonymous>:3:19> },
// { status: 'fulfilled', value: 'another success' }
// ]
});在上面的例子中,我们创建了一个包含三个 Promise 的数组,并使用 Promise.allSettled() 方法来等待所有 Promise 完成。即使其中有 Promise 被拒绝,最终的结果数组中仍然包含所有 Promise 的状态和结果。
Promise.any()
Promise.any() 方法接受一个 Promise 数组作为参数,并返回一个新的 Promise,该 Promise 在其中任何一个 Promise 解决后解决。如果所有 Promise 都被拒绝,Promise.any() 方法将返回一个 AggregateError 对象,该对象包含所有 Promise 的错误。例如:
// www.javascriptcn.com code example
const promises = [
Promise.reject(new Error('failure 1')),
Promise.resolve('success'),
Promise.reject(new Error('failure 2'))
];
Promise.any(promises).then(result => {
console.log(result); // Output: success
}).catch(error => {
console.error(error); // Output: AggregateError: All promises were rejected
});在上面的例子中,我们创建了一个包含三个 Promise 的数组,并使用 Promise.any() 方法来等待其中任何一个 Promise 解决。由于其中一个 Promise 被解决了,最终的结果为成功。如果所有 Promise 都被拒绝,Promise.any() 方法将抛出一个 AggregateError 对象,该对象包含所有 Promise 的错误。
Promise.try()
Promise.try() 方法接受一个函数作为参数,并返回一个新的 Promise,该 Promise 在函数执行完成后解决。与普通的函数调用不同的是,Promise.try() 方法会自动捕获函数执行过程中的错误,并将其作为 Promise 的拒绝原因。例如:
const fn = () => {
throw new Error('failure');
};
Promise.try(fn).catch(error => {
console.error(error); // Output: Error: failure
});在上面的例子中,我们定义了一个会抛出错误的函数 fn,并使用 Promise.try() 方法来调用它。由于 Promise.try() 方法会自动捕获错误,因此我们可以在 Promise 链式调用中使用 .catch() 方法来处理错误。
示例代码
下面是一个使用 ECMAScript 2020 中的 Promises 的例子:
// www.javascriptcn.com code example
const fetchUser = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const user = { name: 'Alice', age: 25 };
resolve(user);
}, 1000);
});
};
const fetchPosts = (userId) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const posts = [
{ id: 1, userId, title: 'Post 1' },
{ id: 2, userId, title: 'Post 2' },
{ id: 3, userId, title: 'Post 3' }
];
resolve(posts);
}, 1000);
});
};
const fetchComments = (postId) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const comments = [
{ id: 1, postId, text: 'Comment 1' },
{ id: 2, postId, text: 'Comment 2' },
{ id: 3, postId, text: 'Comment 3' }
];
resolve(comments);
}, 1000);
});
};
const userId = 1;
Promise.try(() => {
return fetchUser();
}).then(user => {
console.log(user);
return fetchPosts(user.id);
}).then(posts => {
console.log(posts);
const promises = posts.map(post => fetchComments(post.id));
return Promise.allSettled(promises);
}).then(results => {
console.log(results);
}).catch(error => {
console.error(error);
});在上面的例子中,我们定义了三个异步函数 fetchUser()、fetchPosts() 和 fetchComments(),分别用于获取用户、帖子和评论。我们使用 Promise 的链式调用来依次调用这三个函数,并在最后使用 Promise.allSettled() 方法来等待所有评论的 Promise 完成。在 Promise 的构造函数中使用 reject 函数来处理 Promise 被拒绝时的错误,避免了在 Promise 链式调用中使用 .catch() 方法来捕获错误。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d937c2a941bf71340c3f48