淺談Q的基本實現,淺談Q實現

來源:互聯網
上載者:User

淺談Q的基本實現,淺談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() 傳回值-> promissadd().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)          }).then(function(data){            throw new Error()          }).catch(function(err){            if(err){                console.log("There is a Error!")                console.log(err)            }          })

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.