博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一步一步实现一个Promise A+规范的 Promise之二:链式调用
阅读量:6393 次
发布时间:2019-06-23

本文共 5927 字,大约阅读时间需要 19 分钟。

链式调用

上文有提到标准 Promise 的一些特性,接下来一起来实现 Promise 的链式调用。

来看看标准 Promise 的链式调用:

var fn = new Promise(function (resolve, reject) {        setTimeout(function() {            resolve('oook~')        }, 500)    })        fn.then(function(data) {        console.log('data-1: ', data)        return new Promise(function(resolve, reject) {            setTimeout(function() {                reject('不oook~')            }, 1000)        })    }, function(err) {        console.log('err-1: ', err)    })    .then(function(data) {        console.log('data-2:', data)    }, function(err) {        console.log('err-2: ', err)    })    .then(function(data) {        console.log('data-3:', data)    }, function(err) {        console.log('err-3: ', err)    })复制代码

可以看到,经过0.5秒后输出 data-1: oook~,又经过1秒后输出 err-2: 不oook~,最后输出 data-3: undefined

特征如下:

  • then 方法可以返回普通值,也可以返回一个 Promise 对象。
  • 如果 then 方法返回的是一个 Promise 对象,则会根据这个 Promise 对象里执行的是 resolve 还是 reject 走后一个 then 方法的成功和失败回调(本例在第一个 then 里返回了一个 Promise 对象,并异步调用了 reject ,所以会输出 err-2: 不oook~)。
  • 如果 then 方法返回的是一个普通值(无论走的成功还是失败),那么这个普通值就会被当做下一个 then 里成功回调函数的参数(上面例子最后打出 err-3: undefined 就是因为函数默认返回了普通值 undefined)。

根据以上特征,我们的 Promise 对象需要增加以下处理:

  1. 只有 Promise 对象才有 then 方法,所以我们的 then 方法要支持链式调用的话,需要返回一个新的 Promise 对象,并在这个对象里对要传递的值进行处理
  2. 由于 then 方法的返回值可能是一个普通值,也可能是一个新的 Promise 对象,Promise 对象里可能又是一个 Promise 对象,所以我们需要对这个返回值做一个统一的处理,本例用一个统一的方法 resolvePromise 来处理
代码如下:
Promise.prototype.then = function (onFulfilled, onRejected) {        var _this = this        // 定义一个promise2变量(别问我为什么这么命名,A+规范里就是这么命名的)        var promise2              if (_this.status === 'fulfilled') {             // 返回一个新的promise            promise2 = new Promise(function (resolve, reject) {                // A+ 规范规定,onFulfilled 和 onRejected 都需要异步执行,所以加上一个定时器                setTimeout(function() {                    try {                        // x可能是个普通值,也可能是个promise                        var x = onFulfilled(_this.successVal)                        // x也可能是第三方的 Promise 库,用一个函数统一来处理                        resolvePromise(promise2, x, resolve, reject)                    } catch (e) {                        reject(e)                    }                })            });        }        if (_this.status === 'rejected') {             promise2 = new Promise(function (resolve, reject) {                setTimeout(function() {                    try {                        var x = onRejected(_this.failVal)                        resolvePromise(promise2, x, resolve, reject)                    } catch (e) {                        reject(e)                    }                })            })        }        // 当调用then时,如果是异步操作,就会处于pending状态        if (_this.status === 'pending') {            // 将成功的回调添加到数组中             promise2 = new Promise(function (resolve, reject) {                _this.onFulfilledList.push(function () {                    // 可以看到,我们在每一个 resolve 和 reject 执行的地方都加上了异步                    setTimeout(function() {                        try {                            var x = onFulfilled(_this.successVal)                            resolvePromise(promise2, x, resolve, reject)                        } catch (e) {                            reject(e)                        }                    })                })                                _this.onRejectedList.push(function () {                    setTimeout(function() {                        try {                            var x = onRejected(_this.failVal)                            resolvePromise(promise2, x, resolve, reject)                        } catch (e) {                            reject(e)                        }                    })                })            })        }                return promise2    }        function resolvePromise(p2, x, resolve, reject) {        // 不能返回自己        if (p2 === x) {               return reject(new TypeError('不能循环引用!'))        }        // 上一篇有说过,resolve 和 reject 不能同时执行,所以用一个锁来当开关        var called             // x返回的可能是对象和函数也可能是一个普通的值        if (x !== null && (typeof x === 'object' || typeof x === 'function')) {            try {                            var then = x.then                                if (typeof then === 'function') {                    then.call(x, function (y) {                        // ------- resolve 和 reject 不能同时执行 -------                        if (called) {                            return                        }                        called = true                        // 如果成功的话,y有可能也是个 promise,所以递归继续解析                        resolvePromise(p2, y, resolve, reject)                                            }, function (e) {                        // ------- resolve 和 reject 不能同时执行 -------                        if (called) {                            return                        }                        called = true                        reject(e)                    })                                    } else {                        // 如果是普通值,直接返回成功                    resolve(x)                }                            } catch(e) {                            if (called) {                    return                }                                called = true                reject(e)            }                    } else {            resolve(x)        }    }复制代码

ok,链式调用的处理基本上就完成了,下面来看看效果:

var p = new Promise(function(resolve, reject){        setTimeout(function() {            resolve('完全ooooook~')        }, 500)    })           p.then(function (data) {        console.log('success1: ', data)        return new Promise(function(resolve, reject) {            setTimeout(function() {                reject('啊啊啊啊啊啊啊啊啊')            }, 1000)        })    }, function (err) {        console.log('failed: ', err)    })    .then(function (data) {        console.log('success2: ', data)    }, function(err) {        console.log('failed2: ', err)    })复制代码

结果如下:

结果完全ooooook啊啊啊啊啊啊

转载于:https://juejin.im/post/5afbd4cef265da0b767da5ae

你可能感兴趣的文章
Weblogic项目部署教程
查看>>
Gradle -- buildScript块与allprojects块及根级别的repositories区别
查看>>
远程SSH连接服务与基本排错
查看>>
Objective-C学习笔记(十九)——对象方法和类方法的相互调用
查看>>
win10 WmiPrvSE.exe WMI Provider 占用CPU过高的问题
查看>>
hdu 4945 2048(DP)
查看>>
论文阅读:CNN-RNN: A Unified Framework for Multi-label Image Classification
查看>>
开篇有益-解析微软微服务架构eShopOnContainers(一)
查看>>
IE新发现
查看>>
quick check
查看>>
Debug时含有的子元素,在代码里获取不到的问题
查看>>
UVA 11020 - Efficient Solutions(set)
查看>>
RStudio版本号管理 整合Git
查看>>
使用 PHPMailer 发送邮件
查看>>
文件系统管理 之 Linux 创建文件系统及挂载文件系统流程详解
查看>>
CSS选择器学习小结
查看>>
什么叫贸工技发展模式?什么叫技工贸发展模式?
查看>>
MyEclipse for Spring 10.0: GWT 2.1 and Spring Scaffolding
查看>>
水木-搜索引擎技术版
查看>>
yiStack平台维护
查看>>