• 一个简单的Promise 实现


    用了这么长时间的promise,也看了很多关于promise 的文章博客,对promise 算是些了解。但是要更深的理解promise,最好的办法还是自己实现一个。

      我大概清楚promise 是对异步概念的包装,当你拿到一个promise 对象,你并不是拿到你想要的值,而只是这个值的一个“承诺”。这个承诺可能被实现,从而你可以拿到最终想要的值,但也可能被拒绝,然后得到原因。关于promise 对编程风格的改善可以网上有很多文章可以参考,比如这篇

    var promise = new Promise(function (resolve, reject) {
        setTimeout(function(){
            resolve(1);
        }, 1000);
    }).then(function(n) {
        var p = new Promise(function(resolve, reject) {
            setTimeout(function() {
                resolve(n + 2);
            }, 2000);
        })
        return p;
    }).then(function(r) {
        console.log(r);
    })

    上面是一个使用promise 的例子,整个流程需要经过两个异步操作的处理。第一个异步操作是要花费1秒得到整数1,紧接着花费2秒将前一个操作的返回值加上2。

    最后等待所有操作完成后将结果打印。 1 —> 1+2 —> log(3)

        既然是异步操作,你怎么能保证then 过去的函数一定被调用呢?如果还没等then 执行就resolve 了,这样怎么保证回调依然被执行的?答案就是:其实promise 是个状态机,初试状态是pending,当异步操作完成后变为resolved,或者被拒绝变为rejected。那么每当我then 的时候,如果是pending 状态就把这个回调存起来,如果是resolve 状态就立即执行这个回调。

        为了能一直then 下去,then必须返回一个promise,这样我们可以构造出一系列then 链条,链条上的每个promise 都观察着前一个promise,一旦前一个promise 被实现,后续的一个promise 立即被执行,如此传递下去。当然如果其中一环被拒绝的话,整个链条就断了,后续不再执行。

    Version 1:

    var PENDING = 0,
        RESOLVED = 1,
        REJECTED = 2;
    
    function Promise(fn) {
        var state = PENDING;
        var value;
        var callback;
    
        var doResolve = function(_value) {
            if (state === PENDING) {
                value = _value;
                state = RESOLVED;
                if (callback)
                    callback(value);
            } else {
                throw new Error("A promise can only been resolved once.");
            }
        }var doReject = function(_reason) {
            state = REJECTED;
            throw _reason;
        }
    
        this.then = function (_callback) {
            return new Promise(function (_resolve, _reject) {
                var dummy_callback = function (_value) {
                    _resolve(_callback(_value));
                }
                if (state === PENDING) {
                    callback = dummy_callback
                } else {
                    dummy_callback(value);
                }
            });
        }
    
        fn(doResolve, doReject);
    }

    上面的代码实现了一个简单的promise, 但是有一个很严重的问题,无法处理返回promise 的情况(文章开头的那个例子),如果其中一个promise 返回的是另一个promise,那么我们应该把这个新的promise 纳入链条,等待其resolve 后再继续执行剩下的链条。

    Version2:

    var PENDING = 0,
            RESOLVED = 1,
            REJECTED = 2;
    
    function Promise(fn) {
        var state = PENDING;
        var value;
        var callback;
    
        var doResolve = function(_value) {
            if (state === PENDING) {
                value = _value;
                state = RESOLVED;
                if (callback)
                    callback(value);
            } else {
                throw new Error("A promise can only been resolved once.");
            }
        }
    
        var real_resolve = function (_value) {
            if (_value && typeof _value.then === "function") {
                _value.then(doResolve);
            } else {
                doResolve(_value);
            }
        }
    
        var doReject = function(_reason) {
            state = REJECTED;
            throw _reason;
        }
    
        this.then = function (_callback) {
            return new Promise(function (_resolve, _reject) {
                var dummy_callback = function (_value) {
                    _resolve(_callback(_value));
                }
                if (state === PENDING) {
                    callback = dummy_callback
                } else {
                    dummy_callback(value);
                }
            });
        }
    
        fn(real_resolve, doReject);
    }

    我在doResolve 之前加了一个real_resolve 用来处理万一reolsve一个promise 的情况,这里投了一个懒,直接调用了value.then 创建一个新的promise 加入链条。但是本质上可以用value本身。虽然有待改进,但是目的已经达到了,这就是一个简单的promise 实现。

    参考:https://www.promisejs.org/implementing/

       https://github.com/kriskowal/q/blob/v1/design/README.js

  • 相关阅读:
    UESTC_秋实大哥与时空漫游 2015 UESTC Training for Graph Theory<Problem C>
    UESTC_秋实大哥带我飞 2015 UESTC Training for Graph Theory<Problem B>
    UESTC_秋实大哥与连锁快餐店 2015 UESTC Training for Graph Theory<Problem A>
    UESTC_酱神寻宝 2015 UESTC Training for Dynamic Programming<Problem O>
    UESTC_导弹拦截 2015 UESTC Training for Dynamic Programming<Problem N>
    [error] MFC错误不能将参数1从"const char [3]"转换为"const wchar_t *"
    DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏的详细解释
    error MSB4044: 未给任务“CppClean”的必需参数“FoldersToClean”赋值
    关于vs2008的error C2440
    MFC m_hWnd 和 this指针
  • 原文地址:https://www.cnblogs.com/agentgamer/p/4710222.html
Copyright © 2020-2023  润新知