ES6-Promise
基本概念
做异步请求时,我们往往会在请求成功的回调函数里继续写函数,或者继续发送异步,继续回调,回调函数里又回调,一层一层嵌套,就会形成回调地狱。这会使我们的代码可读性变差,不好维护,性能也下降,promise可以解决回调地狱的问题
Promise起到代理的作用,被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法,这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象
Promise对象用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值
一个Promise有以下几种状态:
pending: 初始状态,既不是成功,也不是失败状态fulfilled: 意味着操作成功完成rejected: 意味着操作失败
只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
Promise对象只可能会发生两种改变:
pending状态变为fulfilled状态并传递一个值给相应的状态处理方法pending状态变为rejected并传递失败信息
当其中任一种情况出现时,Promise对象的then方法绑定的处理方法就会被调用,then方法包含两个函数作为参数:onfulfilled和onrejected
当Promise状态为fulfilled时,调用onfulfilled方法,反之调用onrejected方法

基本用法
Promise对象是一个构造函数,用来生成Promise实例
1 | let promise = new Promise((resolve, reject) => { |
可以看到,Promise构造函数接受一个函数作为参数,而该函数的两个参数分别为resolve函数和reject函数
当异步操作成功,也即是从
pending状态变为fulfilled状态时,调用resolve,并将异步操作的结果作为参数传递出去当异步操作失败,也即是从
pending状态变为rejected状态时,调用reject,并将异步操作的结果作为参数传递出去
在Promise实例生成以后,可使用then方法分别指定fulfilled和rejected状态的回调函数
1 | promise.then(value => { |
来看一个例子
1 | function timeout(ms) { |
timeout方法返回一个Promise实例,表示过一段时间后执行,当Promise状态变为fulfilled时就会触发then绑定的回调函数
Promise在新建后会立刻执行,then方法指定的回调函数会在当前脚本所有同步任务执行完之后才会执行
1 | let promise = new Promise((resolve, reject) => { |
当异步操作失败,调用reject,其参数通常是Error对象的实例
1 | function loadImageAsync(url) { |
Promise对象也可以作为参数被传入resolve中
1 | let promise1 = new Promise((resolve, reject) => { |
promise1的状态在3秒后改变,promise2的状态在1秒后改变,由于promise2返回的是promise1,因此1秒后promise2的状态由promise1决定,故在两秒后触发catch
调用resolve或者reject并不会终止Promise的执行
1 | new Promise((resolve, reject) => { |
一般在resolve或者reject前加return
1 | new Promise((resolve, reject) => { |
实例方法
Promise.prototype.then()
该方法可以为Promise实例添加状态改变时的回调函数
1 | Promise.prototype.then(onFulfilled[, onRejected]) |
onFulfilled: 第一个参数是fulfilled状态的回调函数onRejected: 第二个参数是rejected状态的回调函数,可选
1 | function f(flag) { |
当一个Promise成功或者失败,具体的返回值依据以下规则返回:
如果
then中的回调函数返回一个值,那么then返回的Promise将会成为fulfilled状态,并且将返回的值作为fulfilled状态的回调函数的参数值如果
then中的回调函数没有返回值,那么then返回的Promise将会成为fulfilled状态,并且该fulfilled状态的回调函数的参数值为undefined如果
then中的回调函数抛出一个错误,那么then返回的Promise将会成为rejected状态,并且将抛出的错误作为rejected状态的回调函数的参数值如果
then中的回调函数返回一个已经是fulfilled状态的Promise,那么then返回的Promise也会成为fulfilled状态,并且将那个Promise的fulfilled状态的回调函数的参数值作为该被返回的Promise的fulfilled状态回调函数的参数值如果
then中的回调函数返回一个已经是rejected状态的Promise,那么then返回的Promise也会成为rejected状态,并且将那个Promise的rejected状态的回调函数的参数值作为该被返回的Promise的rejected状态回调函数的参数值如果
then中的回调函数返回一个未定状态(pending)的Promise,那么then返回Promise的状态也是未定的,并且它的终态与那个Promise的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的
举例来说
1 | let promise = Promise.resolve(123).then(value => { |
then方法返回一个新的Promise对象,故可以使用链式操作
1 | Promise.resolve('a').then(str => { |
Promise.prototype.catch()
该方法用于指定发生错误时的回调函数,相当于.then(null, onRejected)
1 | Promise.prototype.catch(onRejected); |
onRejected
当
Promise被rejected时,被调用的一个函数
1 | var promise = new Promise((resolve, reject) => { |
等效于
1 | var promise = new Promise((resolve, reject) => { |
如果Promise状态已经变成Resolved,则再抛出错误无效
1 | var promise = new Promise((resolve, reject) => { |
Promise对象的错误可以一直向后传递,直到被捕获
1 | var promise = new Promise((resolve, reject) => { |
Promise.prototype.finally()
finally用于指定不管Promise对象最后状态如何都会执行的操作,接受一个
静态方法
Promise.resolve()
Promise.resolve()可以将现有对象转为Promise对象
1 | Promise.resolve('hello').then(value => { |
上面的写法等价于
1 | new Promise(resolve => resolve('hello')).then(value => { |
Promise.resolve可以接受四种参数
Promise 实例
如果参数是
Promise实例,那么该方法不会对其做任何修改,直接返回这个实例1
2
3
4
5
6var p1 = new Promise(resolve => resolve('hello'));
Promise.resolve(p1).then(value => {
console.log(value + ' world');
})
// hello worldthenable 对象
thenable对象是指具有then方法的对象1
2
3
4
5
6
7
8
9
10let thenable = {
then: function (resolve, reject) {
resolve('hello');
}
};
Promise.resolve(thenable).then(value => {
console.log(value);
});
// hello不具有 then 方法的对象或者原始值
Promise.resolve返回一个新的Promise对象,状态为fulfilled,参数将作为回调函数的参数值1
2
3
4
5
6
7
8
9let obj = {
a: 'hello',
b: 'world'
};
Promise.resolve(obj).then(value => {
console.log(value.a + value.b);
});
// helloworld无参数
直接返回一个
fulfilled状态的对象
Promise.reject()
Promise.reject方法返回一个Promise对象,其状态为rejected
1 | Promise.reject(new Error('Error')).catch(error => { |
Promise.all()
Promise.all用于将多个Promise实例包装成一个新的Promise实例
1 | Promise.all(iterable); |
iterable是一个可遍历的对象
如果传入的参数是一个空的对象或不包含任何
Promise对象,则返回一个fullfilled状态的Promise对象1
2
3
4
5
6
7
8
9
10
11
12
13Promise.all([]).then(resolve => {
console.log('resolved');
}, error => {
console.log('rejected');
});
// resolved
--------------------------------------------------------
Promise.all([1, 2, 3]).then(resolve => {
console.log('resolved');
}, error => {
console.log('rejected');
});
// resolved其它情况下,若传入的
Promise状态都变成fulfilled,则返回一个fulfilled状态的Promise,各个实例的返回值组成一个数组,作为回调函数的参数;只要一个Promise状态为rejected,则返回rejected,第一个被rejected的实例的返回值作为回调函数的参数1
2
3
4
5
6
7
8var p1 = Promise.resolve('hello'),
p2 = Promise.resolve(' '),
p3 = Promise.resolve('world');
Promise.all([p1, p2, p3]).then(value => {
console.log(value.join(''));
});
// hello world1
2
3
4
5
6
7
8
9
10var p1 = Promise.resolve('hello'),
p2 = Promise.reject(new Error('error')),
p3 = Promise.resolve('world');
Promise.all([p1, p2, p3]).then(value => {
console.log(value.join(''));
}, error => {
console.log(error);
});
// Error: error
Promise.race()
Promise.all同样用于将多个Promise实例包装成一个新的Promise实例,与Promise.all不同的是,返回的Promise的状态取决于最先改变的实例
1 | var p1 = new Promise((resolve, reject) => { |
如果将上面p3的时间改为20,则会报错
1 | var p1 = new Promise((resolve, reject) => { |
Promise.allSettled()
与Promise.all类似,用于将多个Promise实例包装成一个新的Promise实例,但不同之处在于会返回每个实例的状态
1 | var p1 = Promise.resolve('hello'), |