Javascript 笔记:Promise
Promise 提供了一种异步编程的模式,大大简化化异步编程的难度。
这篇文章主要是记录了它的基本概念和使用方式。
基本概念
Promise 是异步编程的一种新的解决方案和规范。ES6将其写进了语言标准,统一了用法,原生提供了 Promise 对象。
Promise 对象, 可以用同步的表现形式来书写异步代码(也就是说,代码看起来是同步的,但本质上的运行过程是异步的)。使用 Promise 主要有以下优点:
- 可以很好地解决ES5中的回调地狱的问题(避免了层层嵌套的回调函数)。
- 统一规范、语法简洁、可读性和和可维护性强。
- Promise 对象提供了简洁的 API,使得管理异步任务更方便、更灵活。
从语法上讲,Promise 是一个构造函数。从功能上来说,Promise 对象用于封装一个异步操作,并获取其成功/ 失败的结果值。
使用 Promise 处理异步任务的基本代码结构如下,我们先来认识一下:
1 | // 使用 Promise 处理异步任务的基本模型 |
Promise 处理异步的基本流程如上所示,可以简化为如下的结构:
1 | const promise = new Promise(executor); |
Promise 是一个类,通过 new Promise() 进行实例化,构造出一个 Promise 实例对象。
- Promise
的构造函数中需要传入一个参数,这个参数是一个回调函数,常用于处理异步任务。这个回调函数有一个专有名词叫
executor(执行器),因为在 new Promise() 时,这个函数会立即执行。
可以在该回调函数中传入两个参数:resolve 和
reject。我们可以在适当的时机执行 resolve()、reject(),用于改变当前
Promise 实例的状态为成功或失败,其中成功的结果或失败的结果通过参数传入到
resolve()、reject()中,如 resolve(成功的结果) 或
reject(失败的结果),最终将结果传递给 then()
方法的成功回调函数或失败回调函数。
- 当 Promise 状态变为成功时,会触发 then() 方法里的回调函数的执行,对成功的返回结果进行处理。
- 当 Promise 状态变为失败时,会触发 catch() 方法里的回调函数的执行,,对失败的返回结果进行处理。
- then()方法的括号里面有两个参数,分别代表两个回调函数 onFulfilled 和
onRejected,执行的结果为作为参数传递给这两个回调函数,如
onFulfilled(成功的结果) 或 onRejected(失败的结果) :
- 参数1:成功的回调函数。如果 Promise 的状态为 fulfilled(意思是:任务执行成功),则触发 onFulfilled 函数的执行。
- 参数2:失败的回调函数。如果 Promise 的状态为 rejected(意思是,任务执行失败),则触发 onRejected 函数的执行。
- 只有 Promise 的状态被改变之后,才会走到 then() 或者 catch()。也就是说,在 new Promise() 时,如果没有写 resolve(),则 promise.then() 不执行;如果没有写 reject(),则 promise.catch() 不执行。
- resolve() 和 reject() 这两个方法,可以给 promise.then()、promise.catch() 传递参数。
- then() 可以被多次调用,会按照顺序执行。
回调函数 onFulfilled 和 onRejected 的执行依赖 Promise 状态的改变,我们可以将 Promise 划分为三种状态:
- pending:等待中。属于初始状态,既没有被兑现,也没有被拒绝。
- fulfilled:已兑现/已解决/成功。执行了resolve() 时,立即处于该状态,表示 Promise已经被解决,任务执行成功,触发 onFulfilled 函数。
- rejected:已拒绝/失败。执行了 reject()时,立即处于该状态,表示 Promise已经被拒绝,任务执行失败,触发 onRejected 函数。
其状态转换如下所示:
封装异步任务
在使用 Promise 之前,异步任务一般使用回调函数来实现,如下代码所示:
1 | // 封装 ajax 请求:传入回调函数 success 和 fail |
在上面的代码中,定义和执行 ajax 时需要传⼊ success 和 fail 这两个回调函数,进而执行回调函数。
下面可以使用 Promise 封装这个异步任务: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40// 封装 ajax 请求:传入回调函数 success 和 fail
function ajax(url, success, fail) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', url);
xmlhttp.send();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
success && success(xmlhttp.responseText);
} else {
// 这里的 && 符号,意思是:如果传了 fail 参数,就调用后面的 fail();如果没传 fail 参数,就不调用后面的内容。因为 fail 参数不一定会传。
fail && fail(new Error('接口请求失败'));
}
};
}
// 第一步:model层的接口封装
const promiseB = new Promise((resolve, reject) => {
ajax('xxx_a.json', (res) => {
// 这里的 res 是接口的返回结果。返回码 retCode 是动态数据。
if (res.retCode == 0) {
// 接口请求成功时调用
resolve('request success' + res);
} else {
// 接口请求失败时调用
reject({ retCode: -1, msg: 'network error' });
}
});
});
// 第二步:业务层的接口调用。这里的 data 就是 从 resolve 和 reject 传过来的,也就是从接口拿到的数据
promiseB
.then((res) => {
// 从 resolve 获取正常结果
console.log(res);
})
.catch((err) => {
// 从 reject 获取异常结果
console.log(err);
});data.retCode
的值(接口返回码)不同时,可能会走 resolve,也可能会走
reject,这个由你自己的业务决定。
接口返回的数据,一般是
{ retCode: 0, msg: 'qianguyihao' }
这种 json 格式, retCode
为 0 代表请求接口成功,所以前端对应会写
if (res.retCode == 0)
这样的逻辑。
resolve() 传入的参数
执行 resolve()之后,Promise 的状态一定会变成 fulfilled 吗?这是不一定的。
严格来说,在我们调用 resolve 时,如果 resolve()的参数中传入的值本身不是一个Promise,那么会将该 promise 的状态变成 fulfilled。
resolve()的参数中,可以传入哪些值,Promise会进入哪种状态呢?具体情况如下:
- 情况1:如果resolve()中传入普通的值或者普通对象(包括 undefined),那么 Promise 的状态为fulfilled。这个值会作为then()回调的参数。这是最常见的情况。
- 情况2:如果resolve()中传入的是另外一个新的 Promise,那么原 Promise 的状态将交给新的 Promise 决定。
- 情况3:如果resolve()中传入的是一个对象,并且这个对象里有实现then()方法(这种对象称为 thenable 对象),那就会执行该then()方法,并且根据then()方法的结果来决定Promise的状态。
情况3中,我们通常称这个对象为 thenable 对象。thenable 的意思是,在某个对象或者函数中定义了一个 then() 方法,我们就称其为 thenable 对象/thenable函数。注意,thenable对象里面的那个单词只能写 then,不能写其他的单词;如果写其他的单词,就不是 thenable 对象了,就不符合情况3,而是符合情况1。
Promis 方法
then 方法
then() 方法可以被多次调用,如下代码所示: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const myPromise = new Promise((resolve, reject) => {
resolve('qianguyihao');
});
myPromise.then(res => {
console.log('成功回调1');
console.log('res1:', res);
});
myPromise.then(res => {
console.log('成功回调2');
console.log('res2:', res);
});
myPromise.then(res => {
console.log('成功回调3');
console.log('res3', res);
});
打印结果: 1
2
3
4
5
6
7
8成功回调1
res1: qianguyihao
成功回调2
res2: qianguyihao
成功回调3
res3 qianguyihao
代码解释: 当 myPromise 状态为 fulfilled 时,下面的四个 then() 方法都在监听,所以这四个 then() 方法都会收到状态确定的通知,进而都会执行。
此外,then() 被调用多次还有一种链式调用的写法,它的打印结果与上面的打印结果不同,想要了解 Promise 的链式调用,需要先学习 then() 方法的返回值。
then 方法的返回值
then() 方法本身是有返回值的,它会返回一个新的Promise对象。因为 then()方法的返回值永远是一个 Promise 对象,所以我们才可以对它进行链式调用。
Promise 链式调用的伪代码: 1
2// 伪代码
myPromise.then().then().catch()
那么,then()方法返回的 Promise 对象处于什么状态呢?then()方法的参数里,是一个回调函数。这取决于回调函数的返回值是什么。情况如下:
当then()方法中的回调函数在执行时,那么Promise 处于pending状态。
当 then()方法中的回调函数中,手动 return 一个返回值时,那么 Promise 的状态取决于返回值的类型。当返回值这行代码执行完毕后, Promise 会立即决议,进入确定状态(成功 or 失败)。具体情况如下:
- 情况1:如果没有返回值(相当于 return undefined),或者返回值是普通值/普通对象,那么 Promise 的状态为 fulfilled。这个值会作为fulfilled 状态的回调函数的参数值。
- 情况2:如果返回值是另外一个新的 Promise,那么原 Promise(then 方法返回的默认 promise)的状态将交给新的 Promise 决定,这两个 Promise 的状态一致。
- 情况3:如果返回值是一个对象,并且这个对象里有实现 then()方法(这种对象称为 thenable 对象),那就会执行该 then()方法,并且根据then() 方法的结果来决定P romise的状态。
- 情况4:这是一种特殊情况,当 then() 方法传入的回调函数遇到异常或者手动抛出异常时,那么, Promise 处于rejected 状态,并将抛出的错误作为 rejected 状态的回调函数的参数值。
小结: then()方法里,我们可以通过 return 传递结果和状态给下一个新的 Promise。
默认返回值
如果then()方法的回调函数里没写返回值(相当于 return undefined),那么then()方法的返回值是一个新的Promise。新 Promise 的状态为fulfilled,其then()方法里,res的值为 undefined。
then() 链式调用的代码举例:
1 | const myPromise = new Promise((resolve, reject) => { |
打印结果:
1 | 成功回调1 |
代码解释: 第一个 then()里的回调,是由 myPromise 进行决议。第二个then()、第三个then() 也在等待决议。
但是,第二个 then() 的回调是由第一个 then()传入的回调函数,返回的 Promise 进行决议;第三个 then() 的回调是由第二个 then()传入的回调函数,返回的 Promise 进行决议,以此类推。所以,这两个then()里面的打印参数的结果是 undefined,并没有打印 myPromise 的决议结果。
换句话说,第一个 then() 在等待 myPromise 的决议结果,有决议结果后执行;第二个 then() 在等待第一个 then()参数里返回的新 Promise的决议结果,有决议结果后执行;第三个 then() 在等待第二个 then()参数里返回的新 Promise的决议结果,有决议结果后执行。
返回普通值:通过 return 传递数据结果
我们也可以在 then()方法的回调函数里,手动 return 自己想要的数据,比如一个普通值 value1。这个普通值就可以传递给下一个新的Promise。新 Promise 的状态为fulfilled,其then()方法里,res的值为 value1。
代码举例: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23const myPromise = new Promise((resolve, reject) => {
resolve('1号');
});
myPromise
.then(res => {
console.log('res1:', res);
// return一个普通值,把这个值传递给下一个Promise
return '2号';
/*
上面这行 return,相当于:
return new Promise((resolve, reject)=> {
resolve('2号');
})
*/
})
.then(res => {
// res可以接收到上一个 Promise 传递的值
console.log('res2:', res);
})
.then(res => {
console.log('res3:', res);
});
返回结果:
1 | res1: 1号 |
返回新的 Promise
情况1、在 then() 方法的回调函数中 return 一个成功的新
Promise,那么,then()返回的Promise
也是成功状态。相当于把新Promise的成功结果传递出去。代码举例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20const promise1 = new Promise((resolve, reject) => {
resolve('qianguyihao fulfilled 1');
});
const promise2 = new Promise((resolve, reject) => {
resolve('qianguyihao fulfilled 2');
});
promise1
.then(res => {
console.log('res1:', res);
return promise2;
})
.then(res => {
// 监听 promise2 的成功状态
console.log('res2:', res);
})
.then(res => {
console.log('res3', res);
});
打印结果: 1
2
3res1: qianguyihao fulfilled 1
res2: qianguyihao fulfilled 2
res3 undefined
情况2、在 then() 方法的回调函数中 return 一个失败的新
Promise,那么,then()返回的Promise
也是失败状态。再继续往下走,会怎么样?相当于把新Promise
的失败原因传递出去。代码举例: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26const promise1 = new Promise((resolve, reject) => {
resolve('qianguyihao fulfilled 1');
});
const promise2 = new Promise((resolve, reject) => {
reject('qianguyihao rejected 2');
});
promise1
.then(res => {
console.log('res1:', res);
// return 一个 失败的 Promise
return promise2;
})
.then(res => {
console.log('res2:', res);
}, err => {
// 如果 promise2 为失败状态,可以通过 then() 的第二个参数(即失败的回调函数)捕获异常,然后就可以继续往下执行其他的代码
console.log('err2:', err);
// 这里相当于 return undefined
})
.then(res => {
console.log('res3', res);
}, err => {
console.log('err3:', err);
});1
2
3res1: qianguyihao fulfilled 1
err2: qianguyihao rejected 2
res3: undefined
上方代码可以看到,第二个 Promise 走的是失败回调,这很容易理解。重点是,最后一个 Promise 走的是成功回调,这很出人意料。这主要是因为第二个失败的回调捕获了异常,并返回了一个 undefined 的值,具体的含义见下文的解释。
catch 方法
一个 Promise 的 catch() 方法可以被多次调用。每次调用时我们都可以传入对应 rejected 状态的回调函数。当 Promise 的状态变为 rejected 时,这些回调函数都会被执行。
catch() 被调用多次的伪代码: 1
2
3
4
5const myPromise = new Promise();
myPromise.catch();
myPromise.catch();
myPromise.catch();
代码举例:
1 | const myPromise = new Promise((resolve, reject) => { |
打印结果: 1
2
3
4
5
6
7
8失败回调1
err1: qianguyihao rejected
失败回调2
err2: qianguyihao rejected
失败回调3
err3: qianguyihao rejected
代码解释:
当 myPromise 状态为 rejected 时,下面的四个 catch() 方法都在监听,所以这四个 catch() 方法都会收到状态确定的通知,进而都会执行。
catch 方法的返回值
与 then() 方法类似,catch()方法默认也是有返回值的,它会返回一个新的Promise对象。因为 catch()方法的返回值永远是一个 Promise 对象,所以我们才可以对它进行链式调用。
Promise 链式调用的伪代码: 1
2// 伪代码
myPromise.then().then().catch().then()
上方代码中,因为 myPromise.catch() 的返回值本身就是一个 Promise,所以才可以继续调用 then()、继续调用 catch()。
与 then() 方法类似,catch()方法返回的 Promise 对象处于什么状态呢?catch()方法的参数里,是一个回调函数。这取决于回调函数的返回值是什么。情况如下:
当catch()方法中的回调函数在执行时,那么Promise 处于 pending 状态。
当 catch方法中的回调函数中,手动 return 一个返回值时,那么 Promise 的状态取决于返回值的类型。当返回值这行代码执行完毕后, Promise 会立即决议,进入确定状态(成功 or 失败),进而触发下一个then/catch 函数的执行。同时可以给下一个 then/catch 传递参数。具体情况如下:
- 情况1:如果没有返回值(相当于 return undefined),或者返回值是普通值/普通对象,那么 Promise 的状态为fulfilled。这个值会作为then()回调的参数。
- 情况2:如果返回值是另外一个新的 Promise,那么原 Promise(then 方法返回的默认 promise) 的状态将交给新的 Promise 决定。这两个Promise 的状态一致。
- 情况3:如果返回值是一个对象,并且这个对象里有实现then()方法(这种对象称为 thenable 对象),那就会执行该then()方法,并且根据then()方法的结果来决定Promise的状态。
- 情况4:这是一种特殊情况, 当catch()方法传入的回调函数遇到异常或者手动抛出异常时,那么, Promise 处于rejected 状态。
小结: catch()方法里,我们可以通过 return 传递结果 给下一个新的 Promise。
默认返回值
如果 catch() 方法的回调函数里没写返回值(相当于 return undefined),那么 catch() 方法的返回值是一个新的Promise。新 Promise 的状态为fulfilled,其then()方法里,res的值为 undefined。
返回普通值
我们也可以在 catch()方法的回调函数里,手动 return
自己想要的数据,比如一个普通值
value1。这个普通值就可以传递给下一个新的Promise。新 Promise
的状态为fulfilled,其then()方法里,res的值为 value1。 代码举例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21const myPromise = new Promise((resolve, reject) => {
reject('1号');
});
myPromise
.catch(err => {
console.log('err1:', err);
return '2号';
/*
上面这行 return,相当于:
return new Promise((resolve, reject)=> {
resolve('2号');
})
*/
})
.then(res => {
console.log('res2:', res);
})
.then(res => {
console.log('res3:', res);
});
返回结果: 1
2
3err1: 1号
res2: 2号
res3: undefined
catch 方法的执行时机
Promise 抛出 rejected 异常时,一定要捕获并处理,否则会直接报错。在 Promise 中,发生异常时,它会它会找到最近的那个失败回调函数并执行;
找到最近的 catch() 去执行
代码实例: 1
2
3
4
5
6
7
8
9
10
11
12
13
14const myPromise = new Promise((resolve, reject) => {
reject('qianguyihao rejected');
});
myPromise
.then(res => {
console.log('res1:', res);
})
.then(res => {
console.log('res2:', res);
})
.catch(err => {
console.log('err:', err);
});
打印结果:
1 | err: qianguyihao rejected |
上方代码中的 catch() 是属于哪个 Promise 实例的方法呢?其实没有严格的界限。它既可以捕获 myPromise的异常,也可以捕获那两个 then()的异常。
处理失败状态的两种写法
我们有两种写法可以捕获 Promise的失败/异常状态:
- 写法 1:单独写 catch() 方法作为失败的回调函数。
- 写法 2:then()方法里可以传两个参数,第⼀个参数是成功时的回调函数,第⼆个参数是失败时的回调函数。
这两种写法在实战开发中的代码举例如下:
1 | function myPromise() { |
注意事项:
上面这两种写法是等价的,选其中一种写法即可。这两种写法几乎没有区别。
有一点点区别:
myPromise.then(onFulfilled).catch(onRejected)
:既可以捕获到 myPromise 的异常,也可以捕获到 then() 里面的异常。myPromise.then(onFulfilled, onRejected)
:只能捕获到 promise 的异常,无法捕获then()里面的异常。
知识拓展:myPromise.catch().then()
这种写法,只能捕获到
myPromise 里面的异常。
链式调用
实际开发中,我们经常需要先后请求多个接口:发送第一次网络请求后,等待请求结果;有结果后,然后发送第二次网络请求,等待请求结果;有结果后,然后发送第三次网络请求。以此类推。
比如说:在请求完接口 1 的数据data1之后,需要根据data1的数据,继续请求接口 2,获取data2;然后根据data2的数据,继续请求接口 3。换而言之,现在有三个网络请求,请求 2 必须依赖请求 1 的结果,请求 3 必须依赖请求 2 的结果。
如果按照往常的写法,会有三层回调,陷入“回调地狱”的麻烦。
这种场景其实就是接口的多层嵌套调用,在前端的异步编程开发中,经常遇到。有了 Promise 以及更高级的写法之后,我们可以把多层嵌套调用按照线性的方式进行书写,非常优雅。也就是说:Promise 等ES6的写法可以把原本的多层嵌套写法改进为链式写法。
传递回调函数
伪代码举例:
1 | // 封装 ajax 请求:传入请求地址、请求参数,以及回调函数 success 和 fail。 |
上面的代码层层嵌套,可读性很差,而且出现了我们常说的回调地狱问题。
Promise 的嵌套写法
改用 ES6 的 Promise 之后,写法上会稍微改进一些。代码举例如下:
1 | // 【公共方法层】封装 ajax 请求的伪代码。传入请求地址、请求参数,以及回调函数 success 和 fail。 |
上方代码非常经典。在真正的实战中,我们往往需要嵌套请求多个不同的接口,它们的接口请求地址、要处理的 resolve 和 reject 的时机、业务逻辑往往是不同的,所以需要分开封装不同的 Promise 实例。也就是说,如果要调三个不同的接口,建议单独封装三个不同的 Promise 实例:requestData1、requestData2、requestData3。
Promise 的链式调用写法
针对多个不同接口的嵌套调用,采用 Promise 的链式调用写法如下:
1 | requestData1(params_1).then(res1 => { |
上面代码中,then 是可以链式调用的,一旦 return 一个新的 Promise 实例之后,后面的 then() 就可以作为这个新 Promise 在成功后的回调函数。这种扁平化的写法,更方便维护,可读性更好;并且可以更好的管理请求成功和失败的状态。
用 async ... await 封装链式调用
前面讲的 Promise 链式调用是用 then().then().then()
这种写法。其实我们还可以用更高级的写法,也就是用生成器、用
async ... await
改写那段代码。改进之后,代码写起来非常简洁。
说明:生成器是一种特殊的迭代器,async ... await
是生成器的语法糖。
用生成器封装链式调用
代码举例:
1 | // 封装 Promise 链式请求 |
生成器在执行时,是分阶段执行的,每次遇到 next() 方法后就会执行一个阶段,遇到 yield 就会结束当前阶段的执行并暂停。 上方代码中,yield 后面的内容是当前阶段产生的 Promise 对象;yield 前面的内容是要传递给下一个阶段的参数。
用 async ... await 封装链式调用
上面的生成器代码有些晦涩难懂,实际开发中,通常不会这么写。我们更喜欢用 async ... await 语法封装 Promise 的链式调用。async ... await 是属于生成器的语法糖,写起来更简洁直观、更容易理解。
代码举例: 1
2
3
4
5
6
7
8// 封装:用 async ... await 调用 Promise 链式请求
async function getData() {
const res1 = await requestData1(params_1);
const res2 = await requestData2(res1);
const res3 = await requestData3(res2);
}
getData();
上面的代码非常简洁。实际开发中也经常用到,非常实用。
链式调用,如何处理任务失败的情况
在链式调用多个异步任务的Promise时,如果中间有一个任务失败或者异常,要怎么处理呢?是继续往下执行?还是停止执行,直接抛出异常?这取决于你的业务逻辑是怎样的。
常见的处理方案有以下几种,你可以根据具体情况按需选择。
统一处理失败的情况,不继续往下走
针对 a、b、c 这三个请求,不管哪个请求失败,我都希望做统一处理。这种代码要怎么写呢?我们可以在最后面写一个 catch。
由于是统一处理多个请求的异常,所以只要有一个请求失败了,就会马上走到 catch,剩下的请求就不会继续执行。比如说:
- a 请求失败:然后会走到 catch,不执行 b 和 c;
- a 请求成功,b 请求失败:然后会走到 catch,不执行 c。
代码举例如下: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18getPromise('a.json')
.then((res) => {
console.log(res);
return getPromise('b.json'); // 继续请求 b
})
.then((res) => {
// b 请求成功
console.log(res);
return getPromise('c.json'); // 继续请求 c
})
.then((res) => {
// c 请求成功
console.log('c:success');
})
.catch((err) => {
// 统一处理请求失败
console.log(err);
});
中间的任务失败后,如何继续往下走?
在多个Promise的链式调用中,如果中间的某个Promise 执行失败,还想让剩下的其他 Promise 顺利执行的话,那就请在中间那个失败的Promise里加一个失败的回调函数(可以写到then函数的第二个参数里,也可以写到catch函数里)。捕获异常后,便可继续往下执行其他的Promise。
代码举例: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33const promise1 = new Promise((resolve, reject) => {
resolve('qianguyihao fulfilled 1');
});
const promise2 = new Promise((resolve, reject) => {
reject('qianguyihao rejected 2');
});
const promise3 = new Promise((resolve, reject) => {
resolve('qianguyihao fulfilled 3');
});
promise1
.then(res => {
console.log('res1:', res);
// return 一个 失败的 Promise
return promise2;
})
.then(res => {
console.log('res2:', res);
return promise3;
}, err => {
// 如果 promise2 为失败状态,可以通过 then() 的第二个参数(即失败的回调函数)捕获异常,然后就可以继续往下执行其他 Promise
console.log('err2:', err);
// 关键代码:即便 promise2 失败了,也要继续执行 Promise3
return promise3;
})
.then(res => {
console.log('res3', res);
}, err => {
console.log('err3:', err);
});
打印结果: 1
2
3res1: qianguyihao fulfilled 1
err2: qianguyihao rejected 2
res3 qianguyihao fulfilled 3
上方代码中,我们单独处理了 promise2 失败的情况。不管promise2 成功还是失败,我们都想让后续的 promise3 正常执行。
Promise 类的方法简介
Promise 类的方法:可以直接通过大写的Promise.xxx调用的方法。这里的xxx就称之为静态方法。
Promise 的自带 API 提供了如下静态方法:
Promise 的静态方法 | 含义 | 版本 |
---|---|---|
Promise.resolve() | 返回一个成功状态的 Promise 对象 | ES 2015 |
Promise.reject() | 返回一个失败状态的 Promise 对象 | ES 2015 |
Promsie.all() | 所有 Promise 都执行成功才算成功;或者任意一个 Promise 执行失败,就算失败 | ES 2015 |
Proimse.allSettled() | 不论成功与失败,把所有Promise的执行结果全部返回 | ES 2020 |
Promise.race() | Promise集合中,返回第一个执行完成(无论成功与失败)的 Promise | ES 2015 |
Promise.any() | Promise集合中,返回第一个执行成功的Promise | ES 2021 |
参考: