亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

再談Promise

chenjiang3 / 3051人閱讀

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

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

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

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

Promise

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

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

由于then方法支持鏈?zhǔn)交卣{(diào),因此then方法的返回值一定也是Promise對(duì)象,我們?cè)诖撕?jiǎn)單的返回自身,也就是this。

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

答案是:不一定。

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

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

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

代碼

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的代碼很簡(jiǎn)單,只是通過then方法將一系列的回調(diào)函數(shù)push到隊(duì)列中而已。Promise實(shí)例暴露給用戶的也只有一個(gè)then方法。

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

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

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

Deferred

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

每個(gè)Deferred實(shí)例的對(duì)應(yīng)一個(gè)Promise實(shí)例。調(diào)用Deferred實(shí)例的resolve方法,能使Promise注冊(cè)的回調(diào)隊(duì)列中的回調(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實(shí)例返回Promise實(shí)例,并且使用Deferred實(shí)例的resolve方法來觸發(fā)Promise實(shí)例的完成態(tài)回調(diào),并且將上一個(gè)回調(diào)如果有返回值,我們將該返回值作為新的resolve值傳遞給后面的回調(diào)。

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

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

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

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;
                // 最后再加一個(gè)小技巧
                this.promise = value;
                
                return;
            }
        }
    }
}

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

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

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

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

Promise之所以是解決異步的利器,一方面是then方法的鏈?zhǔn)秸{(diào)用,一方面也是因?yàn)?b>resolve方法可以異步調(diào)用,觸發(fā)回調(diào)隊(duì)列。

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

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

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

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

此后我們可以這樣promisify一個(gè)異步函數(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思路,我們寫一個(gè)更一般化的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;
    }
}

舉一個(gè)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)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/80181.html

相關(guān)文章

  • 再談 JavaScript 異步編程

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

    RobinQu 評(píng)論0 收藏0
  • 再談express與koa的對(duì)比

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

    phodal 評(píng)論0 收藏0
  • 理解JS中的Event Loop機(jī)制

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

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

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

    JackJiang 評(píng)論0 收藏0
  • 簡(jiǎn)要總結(jié)microtask和macrotask

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

    yexiaobai 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<