美文网首页
Nodejs Q promise实现初探

Nodejs Q promise实现初探

作者: 泡沫与周期_白羊Jerry | 来源:发表于2016-08-08 09:58 被阅读441次

    前言

    Q库为nodejs提供了一个基于promise的编程方式,从此避免了一层又一层的callback调用。不过Q的灵活性也给我造成了很大困扰,我可以用promise去resolve promise么,我在then里return promise可以么?因此我研究了下Q库的源代码,幸运的是,Q库提供了一份详细的设计文档,极大的方便了我们对其设计思路的理解。

    直接开始

    跳过一些最原始的版本,我们先看看根据promise的最基本工作方式,能想到的最简单的promise实现。

        var defer = function () {
            var pending = [], value;
            return {
                resolve: function (_value) {
                    value = _value;
                    for (var i = 0, ii = pending.length; i < ii; i++) {
                        var callback = pending[i];
                        callback(value);
                    }
                    pending = undefined;
                },
                then: function (callback) {
                    if (pending) {
                        pending.push(callback);
                    } else {
                        callback(value);
                    }
                }
            }
        };
    

    在defer里存储函数,传递到then里的callback会在原defer被resolve时触发,这是最直观的promise实现方式。
    这种实现方式无法实现链接,defer.promise.then.then.then是不能实现的,另外defer.resolve只能用实值而不能用promise。

    为了能够将promise链接起来,then函数必须也return一个promise,为了能够用promise去resolve defer。q提供了一个对实值的封装。

        var ref = function (value) {
            if (value && typeof value.then === "function")
                return value;
            return {
                then: function (callback) {
                    callback(value);
                }};
        };
    

    如果value本身为promise,就返回该promise,如果该value为实值,就返回一个已经被resolve了的promise,resolve value就是这个实值。

        var ref = function (value) {
            if (value && typeof value.then === "function")
                return value;
            return {
                then: function (callback) {
                    return ref(callback(value));
                }};
        };
    

    这个版本将callback的返回值也封装成promise,因此then函数的返回值可以继续用then继续链接下去。不过我们还没法用promise去resolve defer,因此引出了下面这个版本。

        var defer = function () {
        var pending = [], value;
        return {
            resolve: function (_value) {
                if (pending) {
                    value = ref(_value); // values wrapped in a promise
                    for (var i = 0, ii = pending.length; i < ii; i++) {
                        var callback = pending[i];
                        value.then(callback); // then called instead
                    }
                    pending = undefined;
                }
            },
            promise: {
                then: function (_callback) {
                    var result = defer();
                    // callback is wrapped so that its return
                    // value is captured and used to resolve the promise
                    // that "then" returns
                    var callback = function (value) {
                        result.resolve(_callback(value));
                    };
                    if (pending) {
                        pending.push(callback);
                    } else {
                        value.then(callback);
                    }
                    return result.promise;
                }
            }
        };
    };
    

    在resolve一个defer时,defer会将该value封装成一个promise。然后会将目前存储的callbacks传递到该promise的then函数中,callback函数的调用时机取决于该promise的resolve时刻了。
    注意,这里存储的callback也不是通过then函数传递进来的callback了,为了实现then的链接,存储的callback做的实际事情是调用传递进来的callback,并且用结果去resolve内部新建的一个defer,并且then函数返回该新建defer的promise。
    简而言之,then里面传递的callback函数也可以返回一个promise,之后的then链里只有在该promise被resolve时才会被调用。

    因此现在我们的q库可以写出如下的调用方式:

        var deferA = q.defer();
        deferA.promise //promiseA
            .then(function(value){
                //func1
                return promise2;
            })
            .then(function(value){
                //func2
                return promise3;
            });
        defer.resolve(promise1);
    

    这套函数会构造出一个链条:

     deferA ->promiseA -> hidden_deferA -> call func1 -> promise2 -> hidden_defer2 -> call func2 -> promise3
    

    也就是说,每次对一个promise调用then时,它就会创建一个隐藏的defer,返回这个defer的promise,当原promise被resolve时,该defer也会被传递进去的函数生成的结果resolve。

    到这一步为止,就是q的promise的大概实现原理了。然而q为了进一步抽象和提高,做出了一个message机制,以后的文章再仔细研究。

    相关文章

      网友评论

          本文标题:Nodejs Q promise实现初探

          本文链接:https://www.haomeiwen.com/subject/utxrsttx.html