padding(初始状态)
、fulfilled(异步成功之后的状态)
、rejected(异步失败的状态)
,改变状态的方式只有一种
即异步的结果:如果成功状态由padding——>fulfilled;否则状态由padding——>rejected。无法提供其他方式改变状态。new Promise((resolve, reject) => {
if (异步成功后) {
resolve(value)//将Promise的状态由padding改为fulfilled
} else {
reject(error)//将Promise的状态由padding改为rejected
}
}).then(value => {
// resolve回调
}, error => {
// reject回调
})
上面的代码表示如果异步成功后就会调用.then()
里面的第一个参数方法,否则就会调用.then()
里面的第二个参数方法。如果调用resolve
和reject
有参数则会将参数分别传递给回调函数(.then里面的第一个和第二个参数方法)。
resolve
的参数除了正常值外还可以是一个Promise
实例。如:
let p1 = new Promise((resolve, reject) => {
// ...
})
let p2 = new Promise((resolve, reject) => {
// ...
resolve(p1)
})
上面的代码中p1
、p2
为Promise实例。p2
的resolve
将p1
作为参数。即:一个异步操作的结果是返回另一个异步操作。
注意:
这时p1
的状态决定了p2
的状态。如果p1
的状态为padding
那么p2
的回调会等p1
的状态改变后执行(即p1
成功或失败);如果p1
的状态为resolved
或rejected
那么p2
的回调会立即执行。
示例:
let p1 = new Promise((resolve, reject) => {
setTimeout(()=>{
reject(new Error('发生错误嘹'))
},3000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve(p1)
},1000)
}).then(value => {
console.log(value)
}).catch(error=>{
console.log(error)
})
正因为如此上面代码p2
最终执行的是catch()
方法,并不会走then()
方法。
调用resolve
或reject
并不会终结 Promise 的参数函数的执行。
代码示意:
new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('then')
console.log('promise')
},2000)
}).then(value => {
console.log(value)
})
//执行结果
//promise
//then
一般来说上面的console.log('promise')
如果要执行放到回调函数更加规范
.then()的作用是为 Promise 实例添加状态改变时的回调函数
。
.then()方法的第一个参数是resolved
状态的回调函数,第二个参数(可选)是rejected
状态的回调函数。它的返回的是一个新的
Promise实例。因此可以采用链式写法。
getJSON("/post/1.json").then(
post => getJSON(post.commentURL)
).then(
comments => console.log("resolved: ", comments),
err => console.log("rejected: ", err)
)
上面代码中,第一个then
方法指定的回调函数,返回的是另一个Promise
对象。这时,第二个then
方法指定的回调函数,就会等待这个新的Promise
对象状态发生变化。如果变为resolved
,就调用funcA
,如果状态变为rejected
,就调用funcB
。
用于指定发生错误时的回调函数,最好是在.then()的链式调用最后调用一下此方法来捕获异常。它的返回值仍然是个Promise对象
new Promise((resolve, reject) => {
throw new Error('出现错误了')
}).then(value => {
}).catch(error=>{
console.log(error)
})
上面代码中如果Promise对象状态变为resolved
,则会调用then
方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected
,就会调用catch
方法指定的回调函数,处理这个错误。另外,then
方法指定的回调函数,如果运行中抛出错误,也会被catch
方法捕获。
如果 Promise 状态已经变成resolved
,再抛出错误是无效的。
new Promise((resolve, reject) => {
resolve('data')
throw new Error('出现错误了')
}).then(value => {
console.log(value)
}).catch(error=>{
console.log(error)
})
这时不会运行catch()里面的方法
一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。
如果没有使用catch方法指定错误处理的回调函数,Promise 对象即便抛出错误也不会影响到其它代码
finally
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018
引入标准的。
finally
方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled
还是rejected
。这表明,finally
方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
finally本质上是then方法的特例。如下代码是等效的:
promise
.finally(() => {
// 语句
});
// 等同于
promise
.then(
result => {
// 语句
return result;
},
error => {
// 语句
throw error;
}
);
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例
const p = Promise.all([p1, p2, p3])
p1
、p2
、p3
都为Promise实例,如果不是调用Promise.resolve
将它们转成Promise实例。p
的状态由p1
,p2
,p3
共同决定如果它们的状态全都
为fulfilled
则p
的状态变成fulfilled
,此时p1
,p2
,p3
的返回值组成一个数组传递给p
的回调p1
,p2
,p3
中只要有一个为rejected
,则p
的状态变成rejected
,此时第一个被reject
的实例的返回值,会传递给p
的回调函数。p1
,p2
,p3
自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法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: 报错了]
上面代码中,p1
会resolved
,p2
首先会rejected
,但是p2
有自己的catch
方法,该方法返回的是一个新的 Promise 实例,p2
指向的实际上是这个实例。该实例执行完catch
方法后,也会变成resolved
,导致Promise.all()
方法参数里面的两个实例都会resolved
,因此会调用then
方法指定的回调函数,而不会调用catch
方法指定的回调函数。如果p2
没有自己的catch
方法,就会调用Promise.all()
的catch
方法。
此方法和Promise.all()一样接收多个Promise实例,返回一个新的Promise实例。
const p = Promise.race([p1, p2, p3]);
和Promise.all()的不同之处
是只要p1、p2、p3中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数
Promise.resolve()的作用是将现有对象转换成Promise对象。
以下的写法是等效的
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
参数是一个 Promise 实例,这种情况Promise.resolve()什么都不做
参数是具有then
方法的对象(thenable对象)
,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
参数不是具有then方法的对象,或根本就不是对象,Promise.resolve返回一个状态为resolved
的对象
const p = Promise.resolve('Hello');
// 因为p的状态为resolved所以.then()会立即执行
p.then(function (s){
console.log(s)
});
// Hello
这种情况直接返回状态为resolved的Promise对象。如果希望得到一个 Promise 对象,比较方便的方法就是直接调用。
立即resolve
的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。示例:
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
// one
// two
// three
上面代码中,setTimeout(fn, 0)
在下一轮“事件循环”
开始时执行,Promise.resolve()在本轮“事件循环”
结束时执行,console.log(‘one’)则是立即执行,因此最先输出。
返回状态为rejected的Promise对象
以下两种写法等效
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => {
reject('出错了')
})
p.catch(error=>{
console.log(error)
})
// 出错了