1. 基本用法
const promise = new Promise(function(resolve, reject)=> {
if(成功) {
resolve(value)
} else{
reject(error)
}
})
Promise
构造函数接受一个函数作为它的参数。
该函数有两个内置参数,分别是resolve
和reject
,它们是两个js内置函数。
resolve
的作用是把Promise
对象的状态由 pending
变成 resolved
。在异步操作成功时调用,把参数返回出去;
reject
的作用是把Promise
对象的状态由pending
变成 rejected
。在异步操作失败时调用,可以把抛出的错误作为参数返回出去。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
Promise
的实例可以用.then
方法指定成功和失败状态的回调,也可以分别用.then
和.catch
方法指定成功和失败的回调。
用Promise对象实现的 Ajax :
const getJSON = function(url) {
return 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();
});
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});
- Promise 新建后就会立即执行;
- 如果一个异步操作的结果是返回另一个异步操作,内层的状态会逐步传递给外层;
-
resolve
或者reject
的调用,并不会阻碍后续代码的执行;但是一般情况下状态改变后就不进行别的操作了,所以可以加个return
语句;
new Promise((resolve, reject) => {
resolve(1);
console.log(2);
}).then(r => {
console.log(r);
});
// 2
// 1
2. Promise.prototype.then
-
.then
方法接收两个回调,这两个回调分别在状态变为resolved
时调用和rejected
时调用。这两个函数都是可选的,不一定要提供。它们都接受Promise
对象传出的值作为参数。 -
.then
方法的返回值是一个新的Promise
实例,因此可以采用链式调用,前一个方法的返回值会作为后一个.then
的参数。后一个会等待前面的状态改变再被调用。
getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL);
}).then(function (comments) {
console.log("resolved: ", comments);
}, function (err){
console.log("rejected: ", err);
});
3. Promise.prototype.catch
-
.catch()
方法,相当于.then(null, rejection)
或.then(undefined, rejection)
,用于指定发生错误时的回调函数; -
.then()
方法指定的回调函数,如果运行中抛出错误,也会被.catch()
方法捕获; -
.reject()
方法的作用,等同于抛出错误:
const promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
promise.catch(function(error) {
console.log(error);
});
// Error: test
等同于
const promise = new Promise(function(resolve, reject) {
reject(new Error('test'));
});
promise.catch(function(error) {
console.log(error);
});
- 如果
Promise
状态已经变成resolved
,再抛出错误是无效的。因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了:
const promise = new Promise(function(resolve, reject) {
resolve('ok');
throw new Error('test');
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) });
// ok
-
Promise
对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch
语句捕获; - 不推荐使用
.then()
第二个参数来处理失败状态,推荐使用.catch
,因为这种写法可以捕获前面then
方法执行中的错误; - 如果
Promise
对象后没有跟着.catch
方法,Promise
对象抛出的错误不会传递到外层代码,不会阻碍进程。
**
4. Promise.prototype.finally
finally()
方法用于指定不管 Promise
对象最后状态如何,都会执行的操作。它的参数是一个回调函数,不接受任何参数,执行的操作与状态无关。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
5. Promise.all
-
Promise.all
方法接收一个数组或者类数组对象,每一项都是Promise
实例,如果不是也会内部转换。
const p = Promise.all([p1, p2, p3]);
- 只有
p1、p2、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,p1、p2、p3
的返回值作为数组,传递给p的回调函数; - 只要
p1、p2、p3
之中有一个被rejected
,p
的状态就变成rejected
,第一个被reject
的实例的返回值,会传递给p的回调函数; - 如果作为参数的
Promise
实例,自己定义了catch
方法,那么它一旦被rejected
,并不会触发Promise.all()
的catch
方法。因为它调用了自己的catch
,返回了新的Promise
实例,状态为resolved
,统一传递给Promise.all().then()
的回调:
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]
如果p2没有自己的catch方法,就会调用Promise.all()的catch方法:
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// Error: 报错了
6.Promise.any()
const p = Promise.any([p1, p2, p3]);
- 只有
p1、p2、p3
的状态有一个变成fulfilled
,p
的状态就会变成fulfilled
,第一个成功的实例的返回值会作为参数传递给回调; - 如果
p1、p2、p3
都变成rejected
状态,p
的状态就会变成rejected
,p1、p2、p3
抛出的错误作为数组,传递给p的回调函数;
var resolved = Promise.resolve(42);
var rejected = Promise.reject(-1);
var alsoRejected = Promise.reject(Infinity);
Promise.any([resolved, rejected, alsoRejected]).then(function (result) {
console.log(result); // 42
});
Promise.any([rejected, alsoRejected]).catch(function (results) {
console.log(results); // [-1, Infinity]
});
7. Promise.race()
-
Promise.race
方法接收一个数组或者类数组对象,每一项都是Promise
实例,如果不是也会内部转换。
const p = Promise.race([p1, p2, p3]);
- 只要
p1、p2、p3
之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
8. Promise.allSettled()
-
Promise.allSettled()
方法接受一个数组作为参数,数组的每个成员都是一个Promise
对象。 - 等到参数数组的所有
Promise
对象都发生状态变更(不管是fulfilled
还是rejected
),会把结果打包成数组传递给成功的回调:
const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);
const allSettledPromise = Promise.allSettled([resolved, rejected]);
allSettledPromise.then(function (results) {
console.log(results);
});
// [
// { status: 'fulfilled', value: 42 },
// { status: 'rejected', reason: -1 }
// ]
- results的每个成员是一个对象,对象的格式是固定的:
// 异步操作成功时
{status: 'fulfilled', value: value}
// 异步操作失败时
{status: 'rejected', reason: reason}
9. Promise.resolve()
-
Promise.resolve()
可以将现有对象转为Promise
对象:
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
- Promise.resolve()方法的参数分成4种情况:
(1)参数是一个Promise
实例:
这种情况下,Promise.resolve
将不做任何修改、原封不动地返回;
(2)参数是一个具有then
方法的对象:
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
});
(3)参数不是具有then()方法的对象,或根本就不是对象
Promise.resolve()
方法返回一个新的 Promise
对象,状态为resolved
,会立即执行.then
回调;
const p = Promise.resolve('Hello');
p.then(function (s) {
console.log(s)
});
// Hello
(4)不带有任何参数
Promise.resolve()
方法允许调用时不带参数,直接返回一个resolved
状态的 Promise
对象。
const p = Promise.resolve();
p.then(function () {
// ...
});
- 立即
resolve()
的Promise
对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。
setTimeout(function () { // 在下一轮“事件循环”开始时执行
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
// one
// two
// three
10. 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)
});
// 出错了