Promise的概念
Promise A+规范
- 根据
Promise A+规范所言,Promise是一个带有then方法的对象或函数 - 只要满足
Promise A+规范,其就是Promise
javascript
// 对象
const Promise = {
then(...){}
}
// 函数
function Promise(){}
Promise.then = function(...){}

- 只要是一个
Promise,就可以与另一个Promise进行互操作
ES6中的Promise构造函数
- 在
ES6中的Promise构造函数,称之为对Promise A+规范的实现 - 通过该构造函数可以构建一个
promise实例
javascript
new Promise()
- 但是严格来说该构造函数本身并不是一个
Promise,因为它没有then方法,但是通过该构造函数创建的实例带有满足Promise A+的then方法
javascript
const p = new Promise()
p.then(...)
为何需要Promise
- 一项新技术的诞生,目的是为了解决旧技术的存在的痛点和缺陷
- 在没有
Promise的时代,一些异步操作通常需要通过回调函数去获取异步操作的结果 - 当异步操作变得繁琐,或者获取异步操作之后还需要进行另一个异步操作,那么回调函数就会层层嵌套,形成回调地狱
回调地狱
- 回调地狱是形容在异步编程中出现的多层嵌套回调函数的现象
- 当异步操作依赖于前一个操作的结果时,为了保证顺序和正确性,常常会使用回调函数来处理这些操作,如果嵌套的函数层级过多,代码会变得冗余,耦合性强,并且难以维护
javascript
request('/login', (res) => {
console.log('登录成功');
request('/user/info', (res) => {
console.log('获取用户信息');
request('/home/list', (res) => {
console.log('获取首页数据');
request('xxx', (res) => {
...
})
});
});
});
Promise的出现解决的痛点
- 解决回调地狱: 通过
then方法的链式操作,让回调嵌套的变成链式调用,使得代码更加直观 - 个人理解:
Promise并没有真正意义上解决回调地狱的嵌套问题,而是让回调方式变得更加直观
javascript
const promise = new Promise()
promise.then(...)
.then(...)
.then(...)
- 统一 JavaScript 中的异步方案: 提供简洁的链式调用和简易的捕获错误机制,而且支持异步并发执行
javascript
const promise = new Promise()
promise.then(...).catch(...)
Promise的基本使用
Promise构造函数的使用语法如下
javascript
const promise = new Promise((resolve, reject) => {
// 异步任务操作...
});
Promise接受一个函数作为参数,该函数被称为executor,在new Promise时,executor会立即自动执行,executor函数还提供两个函数作为参数
executor函数的两个参数
resolve(value): 当任务成功完成时调用,并附带成功结果valuereject(error): 当任务出现错误时调用,并抛出错误结果error
获取
promise实例返回的结果
- 当调用
resolve回调函数时,会执行Promise实例的then方法传入的回调函数 - 当调用
reject回调函数时,会执行Promise实例的catch方法传入的回调函数
javascript
const promise1 = new Promise((resolve, reject) => {
reslove('success')
});
promise1.then((res) => {
console.log(res) // 'success'
})
const promise2 = new Promise((resolve, reject) => {
reject('error')
});
promise2.catch((err) => {
console.log(err) // 'error'
})
- 也可以通过
then方法传入的第二个回调函数捕获错误,相当于使用catch捕获错误
javascript
const promise = new Promise((resolve, reject) => {
reject('error');
});
promise3.then(
(res) => {
console.log(res);
},
(err) => {
console.log(err); // 'error'
}
);
// 以上写法和下面是一致的
promise3.then((res) => {
console.log(res);
})
promise3.catch((err) => {
console.log(err); // 'error'
})
总结:
new Promise()后,executor函数自动执行- 执行成功则调用
resolve(value),通过then方法传入的第一个函数获取成功结果 - 执行出错后则调用
reject(err),通过then方法传入的第二个函数(或catch方法)捕获错误结果
Promise的三种状态
Promise的使用过程中划分为三个状态 :pending(待定)、fulfilled(已兑现)、rejected(已拒绝)
javascript
const promise = new Promise((resolve, reject) => {
// pending
if(success) {
resolve('success');
}else {
reject('error')
}
})
promise.then((res) => {
// fulfilled
console.log(res);
})
promise.catch((err) => {
// rejected
console.log(err);
})
- 待定(pending): 初始状态,既没有被兑现也没有被拒绝,当执行
executor中的代码时处于该状态 - 已兑现(fulfilled): 意味着操作成功完成,调用
resolve后处于该状态 - 已拒绝(rejected): 意味着操作失败,调用
reject后或抛出异常处于该状态

注意:
Promise状态一旦确定就是不可更改的(锁定)
resolve参数
resolve函数的参数可以有多种格式
- 普通值或对象,参数可在
then方法的回调中获得,状态由pending-->fulfilled
javascript
new Promise((resolve, reject) => {
resolve({ name:'Jimmy' });
}).then((res) => {
console.log(res); // '{ name:'Jimmy' }',此时状态为fulfilled
})
- 传入一个
Promise,那么当前Promise的状态将由传入的Promise来决定,相当于状态进行移交
javascript
const newPormise = new Promise((resolve, reject) => {
reject('error'); // 拒绝
});
new Promise((resolve, reject) => {
resolve(newPormise); // 传入一个Promise,当前Promise状态取决于newPromise
}).then(
(res) => {
console.log('res:', res);
},
(err) => {
console.log('err:', err);
}
);
- 传入带
then方法的对象,那么该对象then方法会执行,且同时决定Promise状态
javascript
const obj = {
then(resolve, reject) {
reject('error');
}
};
new Promise((resolve, reject) => {
resolve(obj);
}).then(
(res) => {
console.log('res:', res);
},
(err) => {
console.log('err:', err); // err: error
}
);
Promise对象方法

then()
then方法接收两个回调函数作为参数,分别在状态更改为fulfilled或rejected时调用
then方法接收的两个参数
fulfilled的回调函数: 当状态变成fulfilled时会执行的函数rejected的回调函数: 当状态变成rejected时会执行的函数
javascript
const promise = new Promise((resolve, reject) => {
resolve('success');
});
promise.then((res) => {
console.log('res:', res); // 'res:success'
},(err) => {
console.log('err:', err);
});
同一个
promise对象可以被调用多次then方法
- 当调用
resolve方法时,所有的then方法传入的回调函数都会被调用
javascript
promise.then((res) => {
console.log('res:', res); // res: success
});
promise.then((res) => {
console.log('res2:', res); // res2: success
});
promise.then((res) => {
console.log('res3:', res); // res3: success
});
then方法传入的回调可以有返回值,并且then方法本身的返回值是一个Promise
- 传入的回调返回普通值,该值会作为
then方法本身返回的Promise的resolve值
javascript
promise
.then((res) => {
return { name: 'Jimmy' };
})
.then((newRes) => {
console.log(newRes); // { name: 'Jimmy' }
});
- 传入的回调返回
Promise,那么then方法本身返回的Promise的状态取决于回调中返回的Promise
javascript
promise
.then((res) => {
return new Promise((resolve, reject) => {
reject(123); // 'rejected'
});
})
.then(
(newRes) => {
console.log(newRes);
},
(err) => { // 触发第二个回调
console.log(err); // 123
}
);
- 传入的回调返回带
then方法的对象,那么then方法本身返回的Promise的状态取决于返回对象中的then方法
javascript
promise
.then((res) => {
return {
then(resolve, reject) {
resolve(456);
}
};
})
.then((newRes) => {
console.log(newRes); // 456
});
catch()
- 当
executor函数调用reject,或者抛出异常时,都会触发catch方法捕获错误
javascript
const promise = new Promise((resolve, reject) => {
reject('error');
});
promise.catch((err) => {
console.log(err); // error
});
- 无论是在
Promise的executor函数,还是其对象的then方法中,只要有reject()或异常抛出,catch方法都会捕获
javascript
const promise = new Promise((resolve, reject) => {
resolve('success');
});
promise
.then((res) => {
console.log(res); // 'success'
throw new Error('error');
})
.catch((err) => {
// 捕获then方法中返回的promise抛出的错误
console.log(err); // Error对象
});
javascript
const promise = new Promise((resolve, reject) => {
reject('error');
});
promise
.then((res) => {
// reject调用,这里是不会执行的
return new Promise((resolve, reject) => {
resolve('success');
});
})
.catch((err) => {
// 这里捕获的是promise的异常,而不是then方法中返回的Promise的异常
console.log(err); // error
});
catch方法也是可以有返回值的,并且本身也是返回一个Promise- 当在
catch方法中的回调返回内容后,返回的内容和catch本身返回的Promise的状态是有关联的
javascript
const promise = new Promise((resolve, reject) => {
reject('error');
});
promise
.catch((err) => {
return 'catch return value'; // 相当于在返回的Promise中resolve('catch return value')
})
.then((res) => {
console.log('then:', res); // then: catch return value
})
.catch((err) => {
console.log('catch:', err);
});
finally()
finally是在ES2018中新增特性,它表示无论Promise对象变成fulfilled还是rejected状态,该方法内的代码最终都会被执行finally方法不接收参数,因为无论前面是fulfilled状态,还是rejected状态,它都会执行
javascript
const promise = new Promise((resolve, reject) => {
resolve('resolve message');
});
promise
.then((res) => {
console.log('res:', res); // res: resolve message
})
.catch((err) => {})
.finally(() => {
console.log('finally code execute'); // finally code execute
});
finally的功能是设置一个处理程序在前面的操作完成后,执行清理,如关闭loading,终止某些连接等
javascript
showLoading(); // 显示loading遮罩
promise
.then((data) => {
console.log('服务器返回的数据:', data);
})
.finally(() => {
hideLoading(); // 请求结束,处理对应数据后,关闭loading遮罩
});
- 由于
finally不处理promise的结果,所以可以将结果或错误传递给下一个合适的处理程序
javascript
new Promise((resolve, reject) => {
resolve('value');
})
.finally(() => console.log('Promise ready')) // 先触发
.then((res) => console.log(res)); // "value"
finally方法的回调函数不返回任何内容,就算有返回值也会默认被忽略
javascript
const promise = new Promise((resolve, reject) => {
resolve('value');
})
promise
.finally(() => 'finally return value';) // 返回值会被忽略
.then((res) => console.log(res)); // 这里输出的是 "value"
- 但是
finally的回调函数可以抛出error, 执行将转到最近的error的处理程序
javascript
const promise = new Promise((resolve, reject) => {
resolve('value');
})
promise
.finally(() => { throw new Error('error'); }) // 先触发
.catch((err) => console.log(err)); // 这里输出finally抛出的错误对象
Promise类方法
then、catch、finally方法都属于Promise的实例方法,存在于Promise.prototype上- 在
Promise类上也有一些静态方法可以使用, 一共有 6 种静态方法
resolve()
- 用结果
value创建一个fulfilled状态的promise,其用法相当于new Promise并执行resolve
javascript
Promise.resolve('success');
// 相当于
new Promise(resolve => resolve('success'))
- 当已经确定返回结果,并且期望返回一个
Promise时,可以使用该方法
Promise.resolve的参数形态 :
- 普通的值或者对象
javascript
Promise.resolve('success');
- 本身是
Promise,并且resolve方法本身返回的Promise状态会取决于参数中的Promise
javascript
const promise2 = Promise.resolve(
new Promise((resolve, reject) => {
reject('error');
})
);
promise2.catch((err) => {
console.log(err); // error
});
- 带
then方法的对象,该对象的then方法也决定resolve本身返回的Promise的状态
javascript
const promise3 = Promise.resolve({
then(resolve, reject) {
reject('error');
}
});
promise3.catch((err) => {
console.log(err); // error
});
reject()
- 用
error创建一个rejected状态的Promise
javascript
Promise.reject('error message')
// 等同于
new Promise((resolve, reject) => reject('error message'))
reject不分情况,不管传入的参数是什么,最后都会返回一个rejected状态的Promise- 在开发中,这个方法几乎从未被使用过
all()
- 有时候希望并行执行多个
promise,并等待所有promise都准备就绪后,再对数据进行处理 - 这时候可以使用
Promise.all(),它接受一个可迭代对象(通常是一个promise数组),并返回一个包含结果的数组 - 当所有给定的
promise都fulfilled状态时,Promise.all()才完成
javascript
const promise1 = new Promise((resolve) => setTimeout(() => resolve(1), 1500));
const promise2 = new Promise((resolve) => setTimeout(() => resolve(2), 1000));
const promise3 = new Promise((resolve) => setTimeout(() => resolve(3), 500));
Promise.all([promise1, promise2, promise3]).then((res) => {
console.log(res); // 3 秒之后输出 [ 1, 2, 3 ]
});
- 注意: 结果数组中元素的顺序与传入的
promise顺序相同,即使第一个promise等待时间最长才fulfilled,但仍是结果数组中的第一个 - 如上所示,第一个放入的是等待
1500ms才完成的promise,在返回结果中它仍是第一个 - 当传入的数组中包含不是
Promise的项,其内部会使用Promise.resolve进行转换
javascript
Promise.all([promise1, promise2, promise3, 'abc']).then((res) => {
console.log(res); // [ 1, 2, 3, 'abc' ]
});
- 如果任意一个
promise变成rejected,那么Promise.all返回的 promise 的状态也是rejected,并且将错误信息 error 返回
javascript
const promise1 = new Promise((resolve, reject) => setTimeout(() => reject('error'), 1500));
const promise2 = new Promise((resolve) => setTimeout(() => resolve(2), 1000));
const promise3 = new Promise((resolve) => setTimeout(() => resolve(3), 500));
Promise.all([promise1, promise2, promise3, 'abc']).catch((err) => {
console.log(err); // error
});
- 注意: 如果其中一个
promise状态变成rejected,错误信息回立马返回,Promise.all马上变成rejected,其他promise的结果均会被忽略,但操作仍需执行
javascript
const promise1 = new Promise((resolve, reject) => setTimeout(() => reject('error message'), 500));
const promise2 = new Promise((resolve) =>
setTimeout(() => {
console.log('会执行');// 这里会输出
resolve(2);
}, 3000)
);
const promise3 = new Promise((resolve) =>
setTimeout(() => {
console.log('会执行'); // 这里会输出
resolve(3);
}, 3000)
);
Promise.all([promise1, promise2, promise3, 'abc']).catch((err) => {
console.log(err); // error message
});

allSettled()
all方法的缺陷: 当其中一个Promise变成rejected状态时,Promise.all返回的新Promise会立即变成rejected状态,对于fulfilled或仍处于pending状态的Promise,是无法获取对应结果的,而且也没有采取任何措施来取消- 在
ES2020中添加了新的API--Promise.allSettled,该方法会在所有传入的Promise状态都变成fulfilled或rejected后,才会有最终的状态,并且返回的Promise一定是fulfilled的
javascript
const promise1 = new Promise((_, reject) => setTimeout(() => reject('error'), 500));
const promise2 = new Promise((resolve) => setTimeout(() => resolve(2), 1000));
const promise3 = new Promise((resolve) => setTimeout(() => resolve(3), 1500));
Promise.allSettled([promise1, promise2, promise3]).then((res) => {
console.log(res);
});
- 该方法仍然返回一个数组,但是该数组由对象组成,如
{ status: "fulfilled", value: result }

- 该方法在一些旧的浏览器中可能需要
polyfills,可以使用all方法实现allSettled
javascript
const rejectHandler = (reason) => ({ status: 'rejected', reason });
const resolveHandler = (value) => ({ status: 'fulfilled', value });
Promise.myAllSettled = (promises) => {
const newPromises = promises.map((p) => Promise.resolve(p).then(resolveHandler, rejectHandler));
return Promise.all(newPromises);
};
race()
- 与
Promise.all类似,但只等待第一个完成的promise并获取其结果或错误信息
javascript
const promise1 = new Promise((_, reject) => setTimeout(() => reject('error message'), 1500));
const promise2 = new Promise((resolve) => setTimeout(() => resolve(2), 500));
const promise3 = new Promise((resolve) => setTimeout(() => resolve(3), 1500));
Promise.race([promise1, promise2, promise3]).then(console.log); // 2
- 当其中一个
Promise状态变成fulfilled或rejected,Promise.race返回的新Promise也完成,其状态取决于最快完成的Promise - 当一个
Promise完成后,后面所有的Promise都会被忽略,但是操作仍继续执行
any()
any方法是ES2021中新增的方法,与Promise.race类似
与
race方法的区别
Promise.any只等待第一个fulfilled的promise,并将其返回,然后决定新返回Promise的状态
javascript
const promise1 = new Promise((_, reject) => setTimeout(() => reject('error message'), 500));
const promise2 = new Promise((_, reject) => setTimeout(() => reject('error message2'), 1000));
const promise3 = new Promise((resolve) => setTimeout(() => resolve(3), 1500));
// 这里会等待1.5秒后输出3,reject的promise是忽略的
Promise.any([promise1, promise2, promise3]).then(console.log); // 3
- 如果所有
promise都是rejected状态,那么any方法会返回带有AggregateError对象的promise,其errors属性中存储着所有错误信息
javascript
const promise1 = new Promise((_, reject) => setTimeout(() => reject('error message'), 500));
const promise2 = new Promise((_, reject) => setTimeout(() => reject('error message2'), 1000));
const promise3 = new Promise((_, reject) => setTimeout(() => reject(3), 1500));
Promise.any([promise1, promise2, promise3]).catch(console.log);
