在 JavaScript 中,Promise 是一种强大的异步编程工具,用于处理异步操作。
Promise 是 JavaScript 中用于处理异步操作的对象,它提供了更清晰和可维护的方式来管理异步任务。Promise 有三种状态:未完成(pending)、已完成(fulfilled)、已拒绝(rejected)。以下是 Promise 的基本语法:
创建一个 Promise 对象:
const myPromise = new Promise((resolve, reject) => {
// 异步操作
// 如果操作成功,调用 resolve
// 如果操作失败,调用 reject
});
在创建 Promise 时,传递一个带有两个参数的函数,通常称为执行函数。这个执行函数接受两个参数:resolve
和 reject
,它们分别用于将 Promise 标记为已完成或已拒绝。
处理 Promise 的结果:
使用 then
方法来处理 Promise 的结果,它接受两个回调函数作为参数,第一个回调用于处理成功的情况,第二个回调用于处理失败的情况。
myPromise.then(
function (result) {
// 处理成功的情况
},
function (error) {
// 处理失败的情况
}
);
你也可以只提供处理成功的回调,或只提供处理失败的回调,取决于你的需求。
首先,让我们看一下如何在 Promise 中处理错误。一个常见的错误处理方式是在 Promise 的 then
方法中传递两个回调函数,一个用于处理成功的情况,另一个用于处理错误的情况。
const p1 = new Promise((resolve, reject) => {
foo.bar(); // 试图调用一个未定义的函数
resolve("hello");
});
p1.then(
function fulfilled() {
// 永远不会到达这里
},
function rejected(err) {
console.log(err); // 输出:ReferenceError: foo is not defined
}
);
在上面的代码中,foo.bar()
会导致一个 ReferenceError
,并且在 p1
的 rejected
处理函数中捕获了这个错误。这是 Promise 错误处理的典型方式。
然而,有时候我们可能会遇到不应该执行错误处理函数的情况。例如,下面的代码中的 p3
是一个自定义的 Promise 对象,它的 then
方法会立即执行并触发一个错误:
var p3 = {
then: function (cb, errcb) {
cb(42);
errcb("嚯哈哈哈哈哈,不应该执行的");
},
};
p3.then(
function fulfilled(val) {
console.log(val); // 输出:42
},
function rejected(err) {
// 不应该运行!
// console.log(err); // 输出:嚯哈哈哈哈哈,不应该执行的
}
);
在这种情况下,错误处理函数也被调用了,尽管我们不希望它执行。为了解决这个问题,我们可以使用 Promise.resolve(..)
来包装 p3
,这将确保只有真正的 Promise 对象才会执行错误处理函数:
Promise.resolve(p3).then(
function fulfilled(val) {
console.log(val); // 输出:42
},
function rejected(err) {
console.log(err); // 永远不会到达这里
}
);
如果在 fullfilled
函数中出现错误,同级的 rejected 是不会捕获的,同级的捕获,只会捕获上一个链出现的错误。
var p = Promise.resolve( 42 );
p.then(
function fulfilled(msg){
// 数字没有string函数,所以会抛出错误
console.log( msg.toLowerCase() );
},
function rejected(err){
// 永远不会到达这里
}
);
Promise 还允许我们构建链式调用,以更清晰地表示和管理异步操作的顺序。在链式调用中,每个 then
方法返回一个新的 Promise,允许我们继续添加操作。
var p4 = Promise.resolve(23);
p4.then(function (v) {
console.log(v); // 输出:23
return v * 2;
})
.then(function (v) {
console.log(v); // 输出:46
});
在上面的代码中,我们首先创建一个解决值为 23 的 Promise,然后通过 then
方法添加了两个操作,分别将值乘以 2并打印结果。
有时候,我们需要在链式调用中进行异步操作,例如使用 setTimeout
。在这种情况下,我们可以返回一个新的 Promise,以便在异步操作完成后继续链式调用:
var p5 = Promise.resolve(24);
p5.then((res) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(res * 2);
}, 3000);
});
}).then(res => {
console.log(res); // 3秒后输出:48
});
在上面的示例中,我们返回了一个新的 Promise,它在 setTimeout
完成后解决,然后我们继续链式调用并输出结果。