1

在前面的ES6 Promise系列文章的第一篇第二篇分别介绍了如何创建动态的Promise和已完成态的Promise。但是前面2篇里面的所有示例都相对简单,没有涉及到链式调用。

我们知道Promise用来处理异步操作,异步操作的执行顺序是相对比较复杂的,如果再涉及到链式调用,则情况会变得更复杂。这篇文章会通过一个相对简单的代码示例来让大家对Promise的执行顺序和异步性有正确的理解,从而可以以此类推处理更复杂的情况。

我们先看代码:

let a = Promise.reject('a').then(() => {
    console.log('a passed')
}).catch(() => {
    console.log('a failed')
});

Promise.reject('b').catch(() => {
    console.log('b failed');
}).then(() => {
    console.log('b passed');
});

以上代码的打印顺序依次是什么呢?可以先自己思考一下。正确的答案是:

b failed
a failed
b passed

如果你的答案是错误的,那就请继续看接下来的分析。对于Promise的链式调用,我建议可以按照下面的步骤去分析代码,这样非常有利于理解:

1: 拆分成非链式调用
2: 排序出正确的job queue

现在我们就来实际应用以下:
1: 拆分成非链式调用

let pa = Promise.reject('a').then(() => {
    console.log('a passed');
});
let pa1 = pa.catch(() => {
    console.log('a failed');
});

let pb = Promise.reject('b').catch(() => {
    console.log('b failed');
});
let pb1 = pb.then(() => {
    console.log('b passed');
});

这一步需要大家理解的一点是:then()和catch()都是返回一个Promise,而且是不同于母Promise的一个新的,完全独立的Promise。这也是Promise可以链式调用的基础。

2: 排序出正确的job queue

//一级Promise
let pa = Promise.reject('a').then(() => {
    console.log('a passed');
});
let pb = Promise.reject('b').catch(() => {
    console.log('b failed');
});

//二级Promise
let pa1 = pa.catch(() => {
    console.log('a failed');
});
let pb1 = pb.then(() => {
    console.log('b passed');
});

给Promise的job queue排序遵循2个原则

1: 一级Promise为一轮,排在前面,依次类推
2: 同一级的Promise根据代码定义顺序决定先后顺序

根据上面的2个原则,
1: 我们首先识别出pa和pb为一级Promise,它们俩肯定是在pa1和pb1前面的。
2: 在同一级里面,根据代码定义顺序,pa在pb前面;pa1在pb1之前
排除了正确的job queue之后,我们再俩看代码的执行结果:
1: pa因为是一个reject状态的Promise,但是它只定义了fulfilled状态的处理函数,没有定义rejected状态的处理函数。根据我们Promise系列第二篇的知识,我们知道'a passed'永远不会被打印出来。
2: 后面的三个Promise就可以按照job queue的顺序执行,所以最终我们得到了前面看到的正确打印结果:

b failed
a failed
b passed

以上就是本篇文章的内容。


nanaistaken
586 声望43 粉丝