Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。ES6 将其写进了语言标准,统一了用法,原生提供了
Promise
对象。— 选自阮一峰博客 -> Promise
Promise
对象有三种形态,pending
,resolved
,rejected
。转换方式只能为 pending => resolved 或 pending => rejected。
Promise 对象用一个函数作为参数,分别处理 2 种结束状态。看以下实例。
const promise = new Promise(function(resolve, reject){
// 类似的异步操作
setTimeout(function(){
if(/*成功*/){
resolve('success');
}, 2000)
})
promise.then(function(resolved_param){
// success
}, function(rejected_param){
// failed
});
1. Promise.prototype.then
用来处理 Promise 对象返回后的状态,2 个参数。
(一般只使用第一个参数,第二个参数用Promise.prototype.catch
来捕获错误)
getJSON("/posts.json")
.then(function (json) {
return json.post;
})
.then(function (post) {
// ...
});
then 方法可以链式调用,参数是上一个 then 函数的返回值。
var promise = new Promise(function(resolve, reject){
resolve('first')
});
promise.then(function(param){
console.log(param);
return 'chain';
}).then(function(str){
console.log(str);
});
// first
// chain
2. Promise.prototype.catch
catch
用来处理reject状态,是.then(null, reject(error))
的别名。用来捕捉错误的回调函数。
Promise 里的错误会沿着链一直传递下去,直到遇到 reject 的回调函数,reject 的回调函数里的错误也可以让后边的 catch 捕获到。
// 写法一
var promise = new Promise(function (resolve, reject) {
try {
throw new Error("throw a error");
} catch (e) {
reject(e);
}
});
promise.catch(function (error) {
console.log(error);
});
// 写法二
var promise = new Promise(function (resolve, reject) {
reject(new Error("test"));
});
promise.catch(function (error) {
console.log(error);
});
3. Promise.all()
Promise.all()
接受一个数组作为参数,将多个 promise 实例包装成新的 Promise。
var p = Promise.all([p1, p2, p3]);
p 的状态有两种
- 当 p1, p2, p3 的状态全部返回 resolved,p 的状态变为resolved,此时 p1, p2, p3 的返回值组成一个数组,传递给 p 的 resolved 回调函数;
- 只要 p1, p2, p3有一个状态是 rejected,p 的状态变为rejected,此时第一个被 reject 的实例的返回值,传递给 p 的 rejected 回调函数。
4. Promise.race()
var p = Promise.race([p1, p2, p3]);
Promise.race()
和.all()
一样,处理一个 Promise 集合,但只要 p1,p2,p3 的其中一个的状态改变,p 的状态随之变化,那个最先改变的 Promise 实例的返回值,传递给 p 的回调函数。
5. Promise.resolve()
该方法用来将一个对象转换为 Promise 对象。
var p = Promise.resolve([param]);
// 等同于
var p = new Promise(function (resolve, reject) {
resolve([param]);
});
Promise.resolve的参数有四种情况:
(1)参数为一个 Promise 对象:
Promise.resolve()会直接返回当前 Promise 对象。
(2)参数是一个原始值
如果是原始值,Promise.resolve
方法返回一个新的 Promise 对象,状态为resolved
。
const p = Promise.resolve("Hello");
p.then(function (s) {
console.log(s);
});
// Hello
上面代码生成一个新的 Promise 对象的实例p
。由于字符串Hello
不属于异步操作(判断方法是字符串对象不具有 then 方法),返回 Promise 实例的状态从一生成就是resolved
,所以回调函数会立即执行。Promise.resolve
方法的参数,会同时传给回调函数。
(*3)没有参数
Promise.resolve
方法允许调用时不带参数,直接返回一个resolved
状态的 Promise 对象。
需要注意的是,立即resolve
的 Promise 对象,是在本轮“事件循环”(event loop)的结束时触发回调函数,而不是在下一轮“事件循环”的开始时。
setTimeout(function () {
console.log("three");
}, 0);
Promise.resolve().then(function () {
console.log("two");
});
console.log("one");
// one
// two
// three
(4)参数是一个thenable
对象
thenable
对象指的是具有then
方法的对象,比如下面这个对象。
let thenable = {
then: function (resolve, reject) {
resolve(42);
}
};
Promise.resolve
方法会将这个对象转为 Promise 对象,然后就立即执行thenable
对象的then
方法。
let thenable = {
then: function (resolve, reject) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function (value) {
console.log(value); // 42
});
上面代码中,thenable
对象的then
方法执行后,对象p1
的状态就变为resolved
,从而立即执行最后那个then
方法指定的回调函数,输出 42。
6. Promise.reject
Promise.reject(reason)
方法也会返回一个新的 Promise 实例,该实例的状态为rejected
。
const p = Promise.reject("出错了");
// 等同于
const p = new Promise((resolve, reject) => reject("出错了"));
p.then(null, function (s) {
console.log(s);
});
// 出错了
上面代码生成一个 Promise 对象的实例p
,状态为rejected
,回调函数会立即执行。
注意,Promise.reject()
方法的参数,会原封不动地作为reject
的理由,变成后续方法的参数。这一点与Promise.resolve
方法不一致。
const thenable = {
then(resolve, reject) {
reject("出错了");
}
};
Promise.reject(thenable).catch((e) => {
console.log(e === thenable);
});
// true
上面代码中,Promise.reject
方法的参数是一个thenable
对象,执行以后,后面catch
方法的参数不是reject
抛出的“出错了”这个字符串,而是thenable
对象。
未完,不知下次什么时候待续 🤔