状态
Promise对象有三种状态:
pending
: 进行中fulfilled
: 已成功rejected
: 已失败
resolve
函数:会由 pending-> fulfilled
, 状态凝固不会再次改变
reject
函数:会由 pending-> rejected
, 状态凝固不会再次改变
创建一个Promise实例
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数,由 JavaScript 引擎提供。
function getNumber(){
const promise = new Promise((resolve, reject) => {
//做一些异步操作
setTimeout(function(){
var num = Math.ceil(Math.random()*10); //ceil对num进行上舍入 生成1-10的随机数
if(num<=5){
return resolve(num);
}
else{
return reject('数字太大了');
}
}, 2000);
});
return promise;
}
调用resolve
或reject
并不会终结 Promise 的参数函数的执行。如果不想执行后续代码,我们可以在resolve
或reject
前面加上return
语句。
new Promise((resolve, reject) => {
resolve(1);
console.log(2);
}).then(r => {
console.log(r);
});
// 2
// 1
上面代码中,调用resolve(1)
以后,后面的console.log(2)
还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。
Promise常用方法
Promise.then()
then
方法可以接受两个参数,第一个对应fulfilled
状态的回调函数,第二个对应rejected
状态的回调函数。第二个参数是可选的,不建议使用,最好使用catch
方法
then
、catch()
方法返回的是一个Promise实例,存在以下三种情况
- 当返回非Promise对象的值时,
then
和catch
都生成一个状态为fulfilled
的Promise对象,并把该返回值传入Promise链的下一环节 - 当返回值为Promise对象时,生成的Promise对象的状态由被返回的Promise对象决定,传入Promise链下一环节的值也由这个被返回的Promise决定
- 当Promise的回调函数中抛出错误时,
then
和catch
都生成一个状态为rejected
的Promise对象,并把抛出的错误对象传入Promise链的下一环节。
getNumber().then(
function(data){
console.log('resolved');
console.log(data);
},
function(reason){
console.log('rejected');
console.log(reason);
}
);
Promise.catch()
catch()
方法效果和写在then的第二个参数里面一样,对应rejected
状态的回调函数。不过它还有另外一个作用:在执行fulfilled
状态的回调函数(也就是上面then
中的第一个参数)时,如果抛出异常了,那么并不会报错卡死js,而是会进到catch
方法中。
catch()
方法返回的还是一个 Promise
实例,因此后面还可以接着调用then()
方法。
getNumber().then(function(data){
console.log('resolved');
console.log(data);
console.log(somedata); //此处的somedata未定义 ReferenceError: somedata is not defined
})
.catch(function(reason){
console.log('rejected');
console.log(reason);
});
Promise.finally()
不管promise
最后的状态,在执行完then
或catch
指定的回调函数以后,都会执行finally
方法指定的回调函数。
finally
方法的回调函数不接受任何参数。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
Promise.all()
Promise.all()
方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
上面代码中,Promise.all()
方法接受一个数组作为参数,p1
、p2
、p3
都是 Promise 实例,如果不是,就会先调用Promise.resolve
方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()
方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
p
的状态由p1
、p2
、p3
决定,分成两种情况。
-
只有
p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数。 -
只要
p1
、p2
、p3
之中有一个被rejected
,p
的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给p
的回调函数。
注意:
Promise.all
方法会按照并行的模式,将所有请求一次性全部发送出去,然后等待接收到全部结果后,按照顺序打印出来。所以,该方法并不适用于继发执行请求
Promise.resolve()
Promise.resolve()
方法会将现有对象转为 Promise 对象,该实例的状态为fulfilled
。
Promise.resolve('burc')
// 等同于
new Promise(resolve => resolve('burc'))
需要注意的是,立即resolve()
的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve('burc').then(function () {
console.log('two');
});
console.log('one');
// one
// two
// three
上面代码中,setTimeout(fn, 0)
在下一轮“事件循环”开始时执行,Promise.resolve()
在本轮“事件循环”结束时执行,console.log('one')
则是立即执行,因此最先输出。
Promise.reject()
Promise.reject(reason)
方法也会返回一个新的 Promise实例,该实例的状态为rejected
。
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))
Promise.reject()
方法的参数,会原封不动地作为reject
的理由,变成后续方法的参数。
Promise.reject('出错了').catch(e => {
console.log(e === '出错了')
})
// true
链式调用
Promise 是异步编程的一种解决方案,它的链式调用成功解决了传统的回调地狱难题,but,公司里的老代码用promise也写出了回调地狱,这很没有精神,下面是代码示例,论如何正确使用promise
promise错误用法 VS promise正确用法