摘要
本文主要收录了关于Promise的一些常用函数和使用技巧,希望能够帮助大家更轻松的使用Promise解决问题。
基础操作
Promise
是解决异步的回调地狱的方案,可以用Promise将一个异步操作进行包裹,然后使用resolve和reject分别对满足和不满足的异步结果进行下一步触发,Promise对象有以下两个特点:
-
对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
-
一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
new Promise()
返回一个Promise的对象,这个对象可以进行对异步结果的操作。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
// 实现一个Ajax
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
Promise.then(successFn, failFn);
当我们需要处理异步返回的结果时,就需要在Promise对象之后使用then
对结果进行处理,then
方法有两个参数,第一个是接受resolve返回的值,也就是成功的操作函数,第二个是接受reject返回的值,失败的操作函数。
getJSON("/posts.json").then(function(json) {
console.log('结果: ' + json);
}, function(error) {
console.error('出错了', error);
});
then
函数的第一个successFn
可以返回一个值,然后在下一个then
的successFn
可以拿到上一个返回的值,然后形成链式调用。
// 利用链式调用进行多次异步操作
// 获取文章
getJSON("/post/1.json").then(function(post) {
setPost(post.article);
// 获取文章评论
return getJSON(post.commentURL);
}).then(function (comments) {
setComments(comments);
}, function (err){
console.log("rejected: ", err);
});
Promise.catch(failFn);
作为 then(null | undefined, failFn)
的缩写,可以放在末尾对之前的then
进行错误监听
const promise = new Promise((resolve, reject) => {
resolve('resolve');
});
promise.then(res => {
console.log(res);
throw 'error msg';
}).catch(err => {
console.log(err)
})
// "resolve"
// "error msg"
一旦遇到报错,就不再执行报错之后的语句。
const promise = new Promise((resolve, reject) => {
resolve('resolve');
});
promise.then(res => {
throw 'error msg';
console.log(res);
}).catch(err => {
console.log(err)
})
// "error msg"
const promise = new Promise((resolve, reject) => {
reject('rejected');
});
promise.then(res => {
throw 'error msg';
console.log(res);
}).catch(err => {
console.log(err)
})
// "rejected"
如果在reject之前进行了resolve,则不会执行reject的操作,反之,在resolve之前进行了reject操作,则不会执行resolve,这遵循了Promise的一旦进行状态转变就不再转变的原则。
如果报错不在当前事件循环,则捕获不到报错
const promise = new Promise((resolve, reject) => {
resolve('resolved')
setTimeout(function () { throw 'error test' }, 0);
});
promise.then(res => {
console.log(res);
}).catch(err => {
console.log('err',err)
})
因为catch是then的一种缩写,所以catch后也可以链式调用then,但是在这之后的then方法中再报错之前的catch方法就捕获不到了。
promise.catch(function(error) {
console.log('oh no', error);
})
.then(function() {
console.log('carry on');
});
// carry on
Promise.finally(onFinally);
Promise 实例的 finally() 方法用于注册一个在 promise 敲定(resolve或reject)时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 方法,但是链式调用其他的方法,finally会固定返回上一个结果。
进阶操作
Promise.all(promiseArr)
Promise.all() 静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
// [3, 42, "foo"]
const promise1 = Promise.reject(3); // reject
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
}).catch(error => {
console.log('error', error)
});
// "error" 3
// then 函数里面不会有任何回应, catch会捕获到第一个reject的值。
但是如果我们给每一个Promise实例都附上catch函数,则可以在all里面获取到对应catch的值,如果catch不返回任何值,则promise all的then中的values对应项为undefined。
Promise.allSettled(promiseArr)
这个函数解决了Promise.all
遇到一个reject就结束的问题,它会执行完所有的promises,然后在then中得到结果,注意这里resolve的结果和reject结果的对象体有稍许不一样。
Promise.any(promiseArr)
Promise.any() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现
时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。
Promise.race(promiseArr)
Promise.race() 静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定
。
Promise.race() 与 Promise.any() 的对比
Promise.race() 是只要有一个Promise 敲定 (状态改变,resolve或者reject)就会返回,resolve则进入then,reject则进入catch。
Promise.any() 是只要有一个Promise 兑现 (resolve)就会返回,resolve之后则进入then,当所有promises都reject则进入catch。