1 Promise

Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件,在ES6得到支持。
且具有以下特点:
对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。

一个简单例子Promise 的例子。

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

2 Promise链及如何终止

2.1 现象

主要问题是:链式调用时,想在下层返回resolve的情况下,需要在中途得到某种resolve结果就终止调用链。(PS:下层可能是调用其他人编写模块,比如参数不对,它仍会返回resolve,出现错误才会reject,本身下层Promise 返回reject是可以打断调用链的)

下面有个链式调用Promise的测试函数

const promiseFun = function(param1){
    return new Promise((resolve, reject)=>{
        resolve(param1);
    });
}
const promiseTest = function(param1, param2){
    return new Promise((resolve, reject)=>{
        promiseFun(1).then((number)=>{
            console.info(`fun1 result:${number}`);
            return promiseFun(2);
        }).then((number)=>{
            console.info(`fun2 result:${number}`);
            return promiseFun(3);
        }).then((number)=>{
            console.info(`fun3 result:${number}`);
            return promiseFun(4);
        }).then((number)=>{
            console.info(`fun4 result:${number}`);
        }).catch((err)=>{
            console.info(`promiseTest error:${err}`);
        });
    });        
}
promiseTest('1','2').then((number)=>{
    console.info(`promiseTest:${number}`);
}).catch((err)=>{
    console.info(`promiseTest failed:${err}`);
});

现在遇到的一个问题是,比如我们在fun2时,我们调用reject 想终止该链式调用,但实际的结果是仍然会跑到

console.info(`fun3 result:${number}`)及console.info(`fun4 result:${number}`)。

PS: 这种想法本身就很奇怪,因为我们调用reject 只是影响promiseTest 下创建那个Promise的状态。也就是调用reject后promiseTest 这个函数会触发onRejected状态。而链式Promise调用状态是由下层Promise对象的状态决定。

即:

        promiseFun(1).then((number)=>{
            console.info(`fun1 result:${number}`);
            return promiseFun(2);
        }).then((number)=>{
            console.info(`fun2 result:${number}`);
           if(number === 2){
                reject(number)
            }
            else{
                return promiseFun(3);
            }
        }).then((number)=>{
            console.info(`fun3 result:${number}`);
            return promiseFun(4);
        }).then((number)=>{
            console.info(`fun4 result:${number}`);
        }).catch((err)=>{
            console.info(`promiseTest error:${err}`);
        });

2.2 原因

Promise的then方法接收两个参数:
Promise.prototype.then(onFulfilled, onRejected)
若onFulfilled或onRejected是一个函数,当函数返回一个新Promise对象时,原Promise对象的状态将跟新对象保持一致。
来自:https://promisesaplus.com/

解释下原因:
为什么我们链式调用中reject没有作用?
因为reject仅仅改变的是外层包的promiseTest 返回Promise状态。而链式调用的状态是由promiseFun 返回的状态决定, 而在第二个链式调用then时我们调用reject改变了promiseTest 那种Promise的状态进而使promiseTest触发onRejected状态打印 promiseTest failed:${err},而链式第二个链式调用中本身没做修改链式调用的状态,所以第三个链式继承了第一个链式调用返回的Promise的resolve状态,导致链式调用继续向下运行。

2.3 解决方案

而针对上面的问题,我们想要在resolve的情况下,中断或终止链式调用。
还是基于Promise的特点:原Promise对象的状态将跟新对象保持一致。

我们仅需要在链式调用中,返回一个pending 状态或reject状态的Promise对象即可。后面then 所有resolve(onFulfilled)的处理函数就都不会跑到了。即:

return (new Promise((resolve, reject)=>{}));//返回pending状态
return (new Promise((resolve, reject)=>{rejcet()}));//返回reject状态 会被最后catch捕获。

在测试代码中就想这样

then((number)=>{
            console.info(`fun2 result:${number}`);
           if(number === 2){return (new Promise((resolve, reject)=>{}));
                reject(number)
            }
            else{
                return promiseFun(3);
}

3 参考链接

https://blog.csdn.net/ambit_tsai/article/details/80635594
http://es6.ruanyifeng.com/#docs/promise

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐