成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

再談Promise

chenjiang3 / 2997人閱讀

摘要:方法完成回調(diào)注冊模式下,對象通過方法調(diào)用,注冊完成態(tài)和失敗態(tài)的回調(diào)函數(shù)。這些回調(diào)函數(shù)組成一個回調(diào)隊列,處理的值。調(diào)用實例的方法,能使注冊的回調(diào)隊列中的回調(diào)函數(shù)依次執(zhí)行。

之前寫了一篇關(guān)于ES6原生Promise的文章。近期又讀樸靈的《深入淺出Node》,里面介紹了一個Promise/Deferred模式。

Promise是解決異步問題的利器。它其實是一種模式。Promise有三種狀態(tài),未完成態(tài)、完成態(tài)、失敗態(tài),相信大家一定不陌生,Promise對象允許使用.then的形式,將回調(diào)放到IO操作等異步方法的主體之外,使代碼優(yōu)美不少。

下面我結(jié)合《深入淺出Node》,介紹一下如何用ES5實現(xiàn)Promise/Deferred模式。相信研究完該實現(xiàn)代碼之后,我們會對Promise的理解更進一步。

Promise

then方法完成回調(diào)注冊

Promise/Deferred模式下,Promise對象通過then方法調(diào)用,注冊完成態(tài)和失敗態(tài)的回調(diào)函數(shù)。

由于then方法支持鏈式回調(diào),因此then方法的返回值一定也是Promise對象,我們在此簡單的返回自身,也就是this。

那么一定有人要問了:then中的回調(diào)函數(shù),可能返回一個新的Promise對象,此后的then調(diào)用是否是在新的Promise對象上調(diào)用的呢?

答案是:不一定。

這個問題其實困擾我很久,直到看了Promise的實現(xiàn)代碼我才想明白。其實then方法的調(diào)用,只不過是注冊了完成態(tài)和失敗態(tài)下的回調(diào)函數(shù)而已。這些回調(diào)函數(shù)組成一個回調(diào)隊列,處理resolve的值。

Promise構(gòu)造函數(shù)注冊回調(diào)隊列

Promise構(gòu)造函數(shù),給每個實例一個queue屬性,將then方法注冊的回調(diào)隊列,保存在Promise實例的回調(diào)隊列中。

代碼

var Promise = function(){
    this.queue = [];
} 

Promise.prototype.then = function(fulfilledHandler, unfulfilledHandler){
    var handler = {};
    if (typeof fulfilledHandler === "function"){
        handler.fulfilled = fulfilledHandler;
    }
    if (typeof unfulfilledHandler === "function"){
        handler.unfulfilled = unfulfilledHandler;
    }
    this.queue.push(handler);
    return this;
}

我們看到,Promise的代碼很簡單,只是通過then方法將一系列的回調(diào)函數(shù)push到隊列中而已。Promise實例暴露給用戶的也只有一個then方法。

這樣我們就可以這樣調(diào)用了:

promise.then(fulfilledFunc1, unfulfilledFunc1)
    .then(fulfilledFunc2, unfulfilledFunc2)
    .then(fulfilledFunc3, unfulfilledFunc3)

那么如何進行狀態(tài)轉(zhuǎn)換呢?下面我就來講一下帶有resolve方法(reject方法同理,下面均以resolve舉例)的Deferred。

Deferred

Deferred實例決定Promise實例的狀態(tài)

每個Deferred實例的對應一個Promise實例。調(diào)用Deferred實例的resolve方法,能使Promise注冊的回調(diào)隊列中的回調(diào)函數(shù)依次執(zhí)行。

先寫部分代碼:

var Deferred = function(){
    this.promise = new Promise();
}

Deferred.protoype.resolve = function(val){
    var handler, value = val;
    while(handler = this.promise.queue.shift()){
        if (handler && handler.fulfilled){
            value = handler.fulfiller(value) && value;
        }
    }
}

這樣我們就能使用Deferred實例返回Promise實例,并且使用Deferred實例的resolve方法來觸發(fā)Promise實例的完成態(tài)回調(diào),并且將上一個回調(diào)如果有返回值,我們將該返回值作為新的resolve值傳遞給后面的回調(diào)。

處理回調(diào)方法返回的Promise實例

根據(jù)Promise模式,回調(diào)函數(shù)返回Promise實例時,下一個then()中的回調(diào)處理的是新的Promise實例。

在之前的代碼實現(xiàn)中,then方法注冊了一系列的回調(diào)函數(shù),這些回調(diào)函數(shù)應該處理新的promise實例。這里我們用了一個小技巧,見代碼:

Deferred.protoype.resolve = function(val){
    var handler, value = val;
    while(handler = this.promise.queue.shift()){
        if (handler && handler.fulfilled){
            value = handler.fulfiller(value) && value;
            // 修改之處在這里:
            if (value && value.isPromise){
                value.queue = this.promise.queue;
                // 最后再加一個小技巧
                this.promise = value;
                
                return;
            }
        }
    }
}

我們將返回promise實例之后的回調(diào)列表原封不動的注冊到返回的promise中,這樣就保證之前then注冊的回調(diào)隊列能繼續(xù)調(diào)用。最后的小技巧可以使舊的deferred實例對應新的promise實例,這樣可以繼續(xù)使用deferred.resolve方法。

為了判斷實例是否是Promise實例,這里簡單的修改Promise構(gòu)造函數(shù):

var Promise = function(){
    this.queue = [];
    this.isPromise = true;
} 

封裝callback方法用于異步調(diào)用

Promise之所以是解決異步的利器,一方面是then方法的鏈式調(diào)用,一方面也是因為resolve方法可以異步調(diào)用,觸發(fā)回調(diào)隊列。

由于以NodeJS為標志的異步方法其回調(diào)函數(shù)類似于這樣:

asyncFunction(param, function(err, data){
    // do something...
});

我們可以封裝一個自己的callback方法,用于異步觸發(fā)resolve方法。

Deferred.prototype.callback = function(err, data){
    if (err){
        this.reject(err);
    }
    this.resolve(data);
}    

此后我們可以這樣promisify一個異步函數(shù):

var async = function(param){
    var defer = new Deferred();
    var args = Array.prototype.silce.call(arguments);
    args.push(defer.callback);
    asyncFunc.apply(null, args);
    return defer.promise;
}
Promisify

由上面的promisify思路,我們寫一個更一般化的promisify函數(shù):

var promisify = function(method){
    return function(){
        var defer = new Deferred();
        var args = Array.prototype.silce.call(arguments, 1);
        args.push(defer.callback);
        asyncFunc.apply(null, args);
        return defer.promise;
    }
}

舉一個Node中文件操作的例子:

readFile = promisify(fs.readFile);

readFile("file1.txt", "utf8").then(function(file1){
    return readFile(file1.trim(), "utf8");
}).then(function(file2){
    console.log(file2);
})

倆字:優(yōu)雅。

結(jié)束

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/80181.html

相關(guān)文章

  • 再談 JavaScript 異步編程

    摘要:隨著前端的發(fā)展,異步這個詞真是越來越常見了。真正帶來革命性改變的是規(guī)范。借助,我們可以這樣完成異步任務(wù)好棒寫起來像同步處理的函數(shù)一樣別著急,少年??偨Y(jié)以上就是筆者總結(jié)的幾種異步編程模式。 隨著前端的發(fā)展,異步這個詞真是越來越常見了。假設(shè)我們現(xiàn)在有這么一個異步任務(wù): 向服務(wù)器發(fā)起數(shù)次請求,每次請求的結(jié)果作為下次請求的參數(shù)。 來看看我們都有哪些處理方法: Callbacks ...

    RobinQu 評論0 收藏0
  • 再談express與koa的對比

    摘要:以前其實寫過一篇和的對比但是后來發(fā)現(xiàn)里面有不少謬誤所以一直惦記著糾正一下之前的錯誤尤其關(guān)于中間件部分的對比這里的就拿更加簡單的代替的執(zhí)行流程通常我們都說的中間件模型是線性的也就是一個一個往下執(zhí)行的如下圖這么說當然是沒錯的但是當我們執(zhí)行下面代 以前其實寫過一篇express和koa的對比, 但是后來發(fā)現(xiàn)里面有不少謬誤. 所以一直惦記著糾正一下之前的錯誤, 尤其關(guān)于中間件部分的對比. 這里...

    phodal 評論0 收藏0
  • 理解JS中的Event Loop機制

    摘要:前言前幾天在理解的事件環(huán)機制中引發(fā)了我對瀏覽器里的好奇。接下來理解瀏覽器中的,先看一張圖堆和棧堆是用戶主動請求而劃分出來的內(nèi)存區(qū)域,比如你,就是將一個對象存入堆中,可以理解為存對象。廢話不多說,直接上圖個人理解。參考資料運行機制詳解再談 前言 前幾天在理解node的事件環(huán)機制中引發(fā)了我對瀏覽器里Event Loop的好奇。我們都知道javascript是單線程的,任務(wù)是需要一個一個按順...

    MASAILA 評論0 收藏0
  • 前端進階系列(八):JS執(zhí)行機制

    摘要:一直以來,對的執(zhí)行機制都是模棱兩可,知道今天看了文章這一次,徹底弄懂執(zhí)行機制和的規(guī)范和實現(xiàn),才對的執(zhí)行機制有了深入的理解,下面是我的學習總結(jié)。個要點是單線程語言是的執(zhí)行機制,為了實現(xiàn)主線程的不阻塞,就這么誕生了。 一直以來,對JS的執(zhí)行機制都是模棱兩可,知道今天看了文章—《這一次,徹底弄懂JavaScript執(zhí)行機制》和《Event Loop的規(guī)范和實現(xiàn)》,才對JS的執(zhí)行機制有了深入的...

    JackJiang 評論0 收藏0
  • 簡要總結(jié)microtask和macrotask

    摘要:眾所周知和都屬于上述異步任務(wù)的一種那到底為什么和會有順序之分這就是我想分析總結(jié)的問題所在了和的作用是為了讓瀏覽器能夠從內(nèi)部獲取的內(nèi)容并確保執(zhí)行棧能夠順序進行。只要執(zhí)行棧沒有其他在執(zhí)行,在每個結(jié)束時,隊列就會在回調(diào)后處理。 前言 我是在做前端面試題中看到了setTimeout和Promise的比較,然后第一次看到了microtask和macrotask的概念,在閱讀了一些文章之后發(fā)現(xiàn)沒有...

    yexiaobai 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<