资讯专栏INFORMATION COLUMN

自己如何实现promise?

kycool / 779人阅读

摘要:如果让你实现一个你会怎么做自己实现的大体思路我们要明确我们需要一个异步的操作方法满足异步回调。所以选择加入作为实现的基础,让函数实现延迟触发。测试代码测试第二版实现返回一个触发返回一个触发

如果让你实现一个 promise ,你会怎么做?

自己实现promise的大体思路

我们要明确我们需要一个异步的操作方法,满足异步回调。所以选择加入setTimeout 作为实现的基础, 让函数实现延迟触发。

保持一个原则,控制 promise 改变状态的只有 promise 构造函数里的 reslove 、 reject 函数。

链式调用的原理, 类似jQuery,它会在调用方法后, return this. 从而形成链式调用。所以我们采用在调用then(fn)、 catch(fn) 后 会返回一个新的 promise 对象, 然而 这个 promise 对象 受到 它的上级promise 对象的状态结果 和 fn 运行结果的控制。

知识点:
里面 应该 用到点 js 作用域 、 函数闭包、 继承 、 上下文 绑定知识、引用传递。

存在问题

cbList、rhList、 cs 这个三个, Promise 对象能直接访问, 如果对其直接操作可能造成 程序紊乱。

代码如有纰漏,望大家指正

var JcPromise = function (fn) {
    // 防止 用户 直接 更改 state
    var state = "wait"
     // state 为 resolve 状态, 回调函数数组
    var cbList = []
     // state 为 reject 状态, 回调函数数组
    var rjList = []
    this.cbList = cbList
    this.rjList = rjList
    // 
    this.cs = undefined
    // 获取 promise 的状态
    this.getState = function () {
        return state
    }
    /* 函数闭包,函数 定义在里面, 防止 外面用户 直接 使用 resolve 和 reject; */
    // Promise成功触发 函数
    var reslove = function (data) {
        this.cs = data
        if (state !== "wait") {
            return
        } else {
            state = "solve"
            while (this.cbList.length) {
                cbList.shift()(data)
            }
        }
    }
   // Promise 拒绝 触发函数
    var reject = function (e) {
        this.cs = e
        if (state !== "wait") {
            return
        } else {
            state = "reject"
            while (rjList.length) {
                rjList.shift()(e)
            }
        }
    }
// 绑定函数 conext 及 this 为当前 promise对象
    reslove = reslove.bind(this)
    reject = reject.bind(this)
// 延迟 触发
    setTimeout(function () {
        fn(reslove, reject)
    }, 0)
}
JcPromise.prototype.then = function (fn) {
    var handleObj = {}
    var nextPromise = new JcPromise(function (r, j) {
        handleObj.r = r
        handleObj.j = j
    })
    var fixFn = function (data) {
        var result = null
        try {
            result = fn(data)
              // 判断result是不是 JcPromise实例。
            if (result instanceof JcPromise) {
                result.then(function (data) {
                    handleObj.r(data)
                }).catch(function (e) {
                    handleObj.j(e)
                })
            } else  {
                handleObj.r(result)
            }
        } catch (e){
            handleObj.j(e)
        }
    }
    //判断当前状态 如果 是 solve 直接 运行, 如果不是,酒吧 fixFn 推入 cbList 数组。
    if (this.getState() === "solve") {
        setTimeout(function () {
            fixFn(this.cs)
        }, 0)
    } else {
        this.cbList.push(fixFn)
    }
    return nextPromise
}
JcPromise.prototype.catch = function (fn) {
    var handleObj = {}
    var nextPromise = new JcPromise(function (r, j) {
        handleObj.r = r
        handleObj.j = j
    })
    var fixFn = function (e) {
        var result = null
        try {
            result = fn(e)
            if (result instanceof JcPromise) {
                result.then(function (data) {
                    handleObj.r(data)
                }).catch(function (e) {
                    handleObj.j(e)
                })
            } else {
                handleObj.r(result)
            }
        } catch (e){
            handleObj.j(e)
        }
    }
    if (this.getState() === "reject") {
        setTimeout(function () {
            fixFn(this.cs)
        }, 0)
    } else {
        this.rjList.push(fixFn)
    }
    return nextPromise
}
// 测试代码
var p = new JcPromise(function(r, j) {
    setTimeout(function() {r(100)}, 3000)
}).then(data => {
    console.log("1", data)
    return new JcPromise((r, j) => {
        setTimeout(() => {
            r("hi")
        }, 3000)
    })
}).then(data => console.log("2", data)).then(function () {
    console.log("xxx", xx + 1)
}).catch(e => console.log(e)).then(data => console.log(data, "end"))

demo 测试
第二版 jcPromise 实现

    var JcPromise = (function() {
        function JcPromise(fn) {
            fn = fn || noop;
            var statusList = ["start", "pending", "succeed", "err"];
            var cbStatus = [0, 1];
            var status = statusList[0];
            var data = null;
            var err = null;
            var that = this;
            var successFn = [];
            var errFn = [];

            function resolve(d) {
                data = d;
                that._changeStatus(2);
            };

            function reject(e) {
                err = e;
                that._changeStatus(3);
            };
            this.getData = function() {
                return data;
            };
            this.getErr = function() {
                return err
            };
            this.getStatus = function() {
                return status
            };
            this._changeStatus = function(idx) {
                switch (status) {
                    case statusList[2]:
                    case statusList[3]:
                        {
                            return false
                        }
                };
                status = statusList[idx];
                if (status === statusList[3]) {
                    setTimeout(function() {
                        that._triggerCatch();
                    }, 0)
                }
                if (status === statusList[2]) {
                    setTimeout(function() {
                        that._triggerThen();
                    }, 0)
                }
            };
            this._pushThenCb = function(cb) {
                successFn.push({
                    status: cbStatus[0],
                    cb: cb
                });
                if (status === statusList[2]) {
                    this._triggerThen();
                }
            };
            this._pushCatchCb = function(cb) {
                errFn.push({
                    status: cbStatus[0],
                    cb: cb
                });
                if (status === statusList[3]) {
                    this._triggerCatch();
                }
            };
            this._triggerThen = function() {
                successFn.map(function(item) {
                    if (item.status === cbStatus[0]) {
                        item.cb(data);
                        item.status = cbStatus[1];
                    }
                })
            };
            this._triggerCatch = function() {
                errFn.map(function(item) {
                    if (item.status === cbStatus[0]) {
                        item.cb(err);
                        item.status = cbStatus[1];
                    }
                })
            };
            this._changeStatus(1);
            this.uuid = uuid++;
            try {
                fn(resolve, reject);
            } catch (e) {
                reject(e)
            }
            return this
        };
        JcPromise.fn = JcPromise.prototype;
        // 返回一个promise
        JcPromise.fn.then = function(cb) {
            var promiseR = null;
            var promiseJ = null;
            var result = null;
            var that = this;
            var fn = function() {
                setTimeout(function() {
                    try {
                        var data = that.getData();
                        result = cb(data);
                        if (typeof result === "object" && result !== null && result.constructor === JcPromise) {
                            result.then(function(data) {
                                promiseR(data)
                            }).catch(function(e) {
                                promiseJ(e)
                            })
                        } else {
                            promiseR(result)
                        }
                    } catch (e) {
                        promiseJ(e)
                    }
                }, 0);
            };
            this._pushThenCb(fn);
            // 触发promise
            return new JcPromise(function(r, j) {
                promiseR = r;
                promiseJ = j;
            });
        };
        // 返回一个promise
        JcPromise.fn.catch = function(cb) {
            var promiseR = null;
            var promiseJ = null;
            var result = null;
            var that = this;
            var fn = function() {
                setTimeout(function() {
                    try {
                        var data = that.getErr();
                        result = cb(data);
                        if (typeof result === "object" && result !== null && result.constructor === JcPromise) {
                            result.then(function(data) {
                                promiseR(data)
                            }).catch(function(e) {
                                promiseJ(e)
                            })
                        } else {
                            promiseR(result)
                        }
                    } catch (e) {
                        promiseJ(e)
                    }
                }, 0)
            };
            this._pushCatchCb(fn);
            // 触发promise
            return new JcPromise(function(r, j) {
                promiseR = r;
                promiseJ = j;
            });
        };
        return JcPromise
    })();

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93453.html

相关文章

  • JavaScript 异步

    摘要:从最开始的到封装后的都在试图解决异步编程过程中的问题。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。写一个符合规范并可配合使用的写一个符合规范并可配合使用的理解的工作原理采用回调函数来处理异步编程。 JavaScript怎么使用循环代替(异步)递归 问题描述 在开发过程中,遇到一个需求:在系统初始化时通过http获取一个第三方服务器端的列表,第三方服务器提供了一个接口,可通过...

    tuniutech 评论0 收藏0
  • 高级前端面试题大汇总(只有试题,没有答案)

    摘要:面试题来源于网络,看一下高级前端的面试题,可以知道自己和高级前端的差距。 面试题来源于网络,看一下高级前端的面试题,可以知道自己和高级前端的差距。有些面试题会重复。 使用过的koa2中间件 koa-body原理 介绍自己写过的中间件 有没有涉及到Cluster 介绍pm2 master挂了的话pm2怎么处理 如何和MySQL进行通信 React声明周期及自己的理解 如何...

    kviccn 评论0 收藏0
  • 2018大厂高级前端面试题汇总

    摘要:面试的公司分别是阿里网易滴滴今日头条有赞挖财沪江饿了么携程喜马拉雅兑吧微医寺库宝宝树海康威视蘑菇街酷家乐百分点和海风教育。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本人于7-8月开始准备面试,过五关斩六将,最终抱得网易归,深深感受到高级前端面试的套路。以下是自己整理的面试题汇总,不敢藏私,统统贡献出来。 面试的公司分...

    zzir 评论0 收藏0

发表评论

0条评论

kycool

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<