浅谈Q的基本实现

从整个的角度来说,Q的实现其实是闭包的一个应用,下文简单说明实现一下Q的基本功能。

GitHub Q的API

实现Q的功能,先了解一下Q的API

通过 https://github.com/kriskowal/q 截取最简单那部分的文档如下:

var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", function (error, text) {
    if (error) {
        deferred.reject(new Error(error));
    } else {
        deferred.resolve(text);
    }
});
return deferred.promise;

可以看到关键的api 有 defer, reject, promiss, resolve,然后文档还涉及到结果的取值,和错误捕捉,包括then, catch, done, 就不再贴出来。

入口

首先 从前四个api开始。 通过第一行代码

var deferred = Q.defer();

那么可明显得出的代码是:

var Q = {
    defer: function(){}
}

然后defer()的返回值deffred拥有3个属性。

var Q = {
    defer: function(){
        return {
            reject: function(error){},
            resolve: function(data){},
            promiss: null //当前还不能确定是个什么值
        }
    }
}

以上基本的代码结构出来了。在来补充promiss的内容。

promiss

问来方便说明,这里先预设一个使用环境。从结果来推导代码实现。

          var add = function(){
            var deferred = Q.defer()
            setTimeout(function(){
                deferred.resolve(2)
            }, 2000)
            return deferred.promise
          }

          add().then(function(data){
            console.log(data)
            return data + 1
          }).then(function(data){
            console.log(data)
          }).then(function(data){
            throw new Error()
          }).catch(function(err){
            if(err){
                console.log("There is a Error!")
                console.log(err)
            }
          })

可以看到上面的add就使用了Q. 先看

add().then(...).then(...).catch(...)

那么可以明确,deffred.promiss至少有三个属性 (then,catch两个加上没有出现的done),并且其中的两个应该返回的是原对象。所以得到

var Q = {
    defer: function(){

        var promiss = {
            then: function(fn){ //接收回调函数做为参数
                // ... do something
                return promiss
            },
            catch: function(fn){
                //... do something
                return promss
            },
            done: function(){}
        }

        return {
            reject: function(error){},
            resolve: function(data){},
            promiss: promiss
        }
    }
}

如此以上,整个Q的基本对象结构出来了。虽然没有实现。

then的实现

  var add = function(){
            var deferred = Q.defer()
            setTimeout(function(){
                deferred.resolve(2)
            }, 2000)
            return deferred.promise
          }

通过上述代码发现, 计算结果是异步的存储的,那么当结果计算完成后,then里面的函数应该执行。如下

var Q = {
    defer: function(){
        var promiss = {
            then: function(fn){ //接收回调函数做为参数
                // ... do something
                return promiss //将自身对象返回很容易做到链式调用
            },
            ...
        }

        return {
            promiss: promiss
            ...
        }
    }
}

所以

add() 返回值-> promiss
add().then() 返回值-> promiss

接着来看 数据的传递。异步后resolve函数得到调用,获取到了实际结果,这个实际的返回值需要给then里面的回调函数。这个无法通过直接调用then来实现数据传递的。因此需要一个中间处理函数。如下:

var Q = {
    defer: function(){
       //定义一个结果处理函数。
        var callResult = function(data){
            //do some thing
        }; 

        var promiss = {
            then: function(fn){ //接收回调函数做为参数
                // ... do something
                return promiss //将自身对象返回很容易做到链式调用
            },
            ...
        }

        return {
            resolve: function(data){
               callResult(data)
            }
            ...
        }
    }
}

做到这里关键点来了,需要解决的问题有两个, 1.怎么在resolve 函数调用时,把结果传给then的回调,并且让它执行? 2.then的返回值怎么需要给下一个then?

闭包的实现就在这里了。闭包的主要作用就是隔离作用域,以及向上层上下文寻找变量。

解决关键,使用个队列 来 存储所then的所有回调,在resolve执行时,执行这个队列里面的所有函数,并且把返回值循环赋值。
下面是完整的代码。

var Q = {
            defer: function(){
                'use strict'
                //正常结果集
                var resultQueue = [];
                //错误处理句柄
                var errorHandle = function(error){};

                var promise = {
                    then: function(fn){
                        //存储每一个then的回调函数,进行统一处理
                        resultQueue.push(fn)
                        return promise
                    },
                    done: function(){
                        return {
                            catch: promise.catch
                        }
                    },
                    catch: function(fn){
                        errorHandle = fn
                    }
                }

                var callAllResultQueue = function(data){
                    for(var i = 0; i < resultQueue.length; i++){
                        data = resultQueue[i](data);
                    }
                }

                return {
                    resolve: function(data){
                        //resolve触发所有then回调函数的执行。
                        callAllResultQueue(data)
                    },
                    reject: function(error){
                        errorHandle(error)
                    }
                    promise: promise
                }
            }
          }


          var add = function(){
            var deferred = Q.defer()
            setTimeout(function(){
                deferred.resolve(2)
            }, 2000)
            return deferred.promise
          }

          add().then(function(data){
            console.log(data)
            return data + 1
          }).then(function(data){
            console.log(data)
          }).catch(function(err){
            if(err){
                console.log("There is a Error!")
                console.log(err)
            }
          })
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值