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

資訊專欄INFORMATION COLUMN

promise/deferred 模式原理分析和實(shí)現(xiàn)

gclove / 3534人閱讀

摘要:三模式模式其實(shí)包含兩部分和。六化在編碼的時(shí)候,想要用進(jìn)行異步操作流程控制,就要將當(dāng)前的異步回調(diào)函數(shù)封裝成。

一、什么是promise/deferred 模式

promise/deferred 模式是,根據(jù)promise/A 或者它的增強(qiáng)修改版promise/A+ 規(guī)范 實(shí)現(xiàn)的promise異步操作的一種實(shí)現(xiàn)方式。

異步的廣度使用使得回調(diào),嵌套出現(xiàn),但是一但出現(xiàn)深度的嵌套,就會讓coding的體驗(yàn)變得相當(dāng)不愉快,而且代碼后期的維護(hù)也是相當(dāng)吃力的。promise/deferred模式的出現(xiàn),會在一定程度上緩解這個(gè)問題。接下來我會根據(jù)promise/a 規(guī)范來介紹promise/deferred模式。
(題外話:什么是規(guī)范,規(guī)范其實(shí)就相當(dāng)于制定的規(guī)則,但卻沒有在代碼層面上有默認(rèn)的具體實(shí)現(xiàn))

二、promise/a

promise/a 提議對單個(gè)異步操作作出了這樣的抽象定義:
1.promise操作只會在以下3種狀態(tài)中的一種:等待態(tài)(Pending)、執(zhí)行態(tài)(Fulfilled)和拒絕態(tài)(Rejected)。
2.promise的狀態(tài)只會出現(xiàn)從等待狀態(tài)向執(zhí)行態(tài)或者拒絕態(tài)轉(zhuǎn)化,不可以逆轉(zhuǎn)。執(zhí)行態(tài)和拒絕態(tài)之間不能相互轉(zhuǎn)換
3.promise狀態(tài)一旦被轉(zhuǎn)換,就不能被更改。

4.在api上,規(guī)范定義比較簡單,只要求promise 必修提供有一個(gè)then方法,以訪問當(dāng)前值、最終值和拒絕原因
then方法接受兩個(gè)參數(shù)
promise.then(onFulfilled,onRejected)
5.then方法的onFulfilled,onRejected 方法都是可選參數(shù),且不是function,都被忽略
6.then()方法返回promise對象,以實(shí)現(xiàn)鏈?zhǔn)綄懛ā?/p> 三、promise/deferred模式

promise/deferred 模式 其實(shí)包含兩部分:Promise 和 Deferred。

Deferred主要是用于內(nèi)部,來維護(hù)異步模型的狀態(tài)。

Promise只要用于外部,通過then()方法,暴露給外部調(diào)用,以添加業(yè)務(wù)邏輯和業(yè)務(wù)的組裝。

promise 和 deferred的關(guān)系圖

從圖中可以看到:

 1.deferred對象通過resolve方法,改變自身狀態(tài)為執(zhí)行態(tài),并觸發(fā)then()方法的onfulfilled回調(diào)函數(shù)
 2.deferred對象通過reject方法,改變自身狀態(tài)為拒絕態(tài),并觸發(fā)then()方法的onrejected回調(diào)函數(shù)

下面 我們就用代碼來實(shí)現(xiàn)一下:

/**
 * Promise 類
 * @constructor
 */
function Promise() {
    this.handler = {};
}

/**
 * promise 對象的then方法
 * @param onFulfilled  當(dāng) promise 執(zhí)行結(jié)束后其必須被調(diào)用,其第一個(gè)參數(shù)為 promise 的終值,其調(diào)用次數(shù)不可超過一次
 * @param onRejected   當(dāng) promise 被拒絕執(zhí)行后其必須被調(diào)用,其第一個(gè)參數(shù)為 promise 的據(jù)因,其調(diào)用次數(shù)不可超過一次
 * @returns {Promise}  規(guī)范定義必修返回 primise對象
 */
Promise.prototype.then = function (onFulfilled, onRejected) {
    var handler = {}
    if (typeof onFulfilled === "function") {
        handler.resolve = onFulfilled
    }
    if (typeof onRejected === "function") {
        handler.reject = onRejected
    }
    this.handler = handler
    return this
}

這里可以看到then方法所做的事情就是講回調(diào)函數(shù)存放起來,為了完成整個(gè)流程,還需要觸發(fā)執(zhí)行這些回調(diào)函數(shù)的地方,而實(shí)現(xiàn)這些功能的對象就叫做deferred(延遲對象)。示范代碼如下

function Deferred() {

    /* 狀態(tài):默認(rèn) 等待態(tài) pending */
    this.state = "pending";

    this.promise = new Promise()
}

Deferred.prototype.resolve = function (obj) {
    this.state = "fulfilled"
    var handler = this.promise.handler
    if (handler && handler.resolve) {
        handler.resolve(obj)
    }
}

Deferred.prototype.reject = function (obj) {
    this.state = "rejected"
    var handler = this.promise.handler
    if (handler && handler.reject) {
        handler.reject(obj)
    }
}

以上已經(jīng)定義好了Promies 和Deferred ,那我們怎么對一個(gè)異步操作函數(shù)進(jìn)行封裝呢?
假如我們有這樣的異步函數(shù)

function asyncDoSomeing(flag, message) {
    setTimeout(function () {
        if (flag) {
            return message
        }
    }, 3000)
}

對其封裝的代碼就是

function asyncDoSomeing(flag, message) {
    var deferred = new Deferred()
    setTimeout(function () {
        if (flag) {
            deferred.resolve(message)
        } else {
            deferred.reject({code: 400, message: "拒絕"})
        }
    }, 3000)
    return deferred.promise
}

最后我們就可以這么使用了

asyncDoSomeing(true, "測試執(zhí)行成功").then(function (message) {
    console.log(message)
}, function (err) {
    console.log(err)
})

到這里只是單個(gè)promise對象的簡單異步的操作控制,但是有熟悉node.js 和angular.js 的同學(xué)就會發(fā)現(xiàn),這個(gè)寫法跟node.js 里面的一個(gè)異步控制流程 q 模塊(https://github.com/kriskowal/q )寫法是一樣的。是的哦 它就是promise/deferred 模式。隨便提一下 Angularjs的$q對象是q的精簡版。

四、鏈?zhǔn)秸{(diào)用
 做到以上的簡單實(shí)現(xiàn),理想的coding方式,應(yīng)該前一個(gè)調(diào)用結(jié)果作為下一個(gè)調(diào)用的輸入,這就是鏈?zhǔn)秸{(diào)用。

為了避免回調(diào)地獄,可以借鑒jquery的鏈?zhǔn)綄懛ā?/p>

$("#tab").eq($(this).index()).show().siblings().hide();

鏈?zhǔn)綄懛ǖ暮诵脑谟?,每個(gè)方法都返回 自身 this。

我們現(xiàn)在需要實(shí)現(xiàn)promise的鏈?zhǔn)秸{(diào)用,前一個(gè)調(diào)用結(jié)果作為下一個(gè)調(diào)用的輸入

 step1.then(step2).then(step3)

現(xiàn)在我們實(shí)現(xiàn)的then方法確實(shí)是返回this的,也就是promise本身,是可以實(shí)現(xiàn)鏈?zhǔn)降摹?br>但是前一個(gè)調(diào)用的結(jié)果卻做不到是下一個(gè)調(diào)用的輸入
下面來改造一下上面的代碼,讓他實(shí)現(xiàn)這個(gè)要求。

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

1.將原本的handler對象改為 一個(gè)數(shù)組,存放所有then方法的回調(diào)。

Promise.prototype.then = function (onFulfilled, onRejected) {
    var handler = {}
    if (typeof onFulfilled === "function") {
        handler.resolve = onFulfilled
    }
    if (typeof onRejected === "function") {
        handler.reject = onRejected
    }
    this.handlerQueue.push(handler)

    return this
}

function Deferred() {
    this.state = "pending"
    this.promise = new Promise()
}

Deferred.prototype.resolve = function (obj) {
    this.state = "fulfilled"
    var promise = this.promise
    var handler = {}
    while (handler = promise.handlerQueue.shift()) {
        if (handler && handler.resolve) {
            var res = handler.resolve(obj)
            if (res && res.isPromise) {
                res.handlerQueue = promise.handlerQueue
                this.promise = res
                return;
            } else {
                obj = res
            }
        }
    }
}

Deferred.prototype.reject = function (obj) {
    this.state = "rejected"
    var promise = this.promise
    var handler = {}
    while (handler = promise.handlerQueue.shift()) {
        if (handler && handler.reject) {
            var res = handler.reject(obj)
            if (res && res.isPromise) {
                res.handlerQueue = promise.handlerQueue
                this.promise = res
                return;
            } else {
                obj = res
            }
        }
    }
}

//------ test-------//
function asyncDosomeing(flag, name) {
    const deferred = new Deferred()
    setTimeout(function () {
        if (flag) {
            deferred.resolve({code: 200, message: "成功", name: name})
        } else {
            deferred.reject({code: 400, message: "失敗", name: name})
        }
    }, 2000)
    return deferred.promise
}
asyncDosomeing(true, "asyncDosomeing1").then(result => {
    console.info(result)
    return asyncDosomeing(false, "asyncDosomeing2")
}).then(result => {
    console.info(result)
    return "dadds"
}).then(result => {
    console.info(result)
})
五、統(tǒng)一的異常處理(拒絕處理)

那現(xiàn)在,我們有個(gè)需求,想實(shí)現(xiàn)所有的拒絕統(tǒng)一在一個(gè)地方處理。而不是每個(gè)then方法都傳一個(gè)rejected 回調(diào),只希望then()方法可以,安安心心的處理成功的回調(diào)。

 step1().then(step2).then(step3).catch(function(err){
// do something when err
})

加一個(gè)catch err 的回調(diào),當(dāng)出現(xiàn)異常就直接到這個(gè)流程上處理。
那我們就在promise 的原型上架一個(gè)catch方法,如下

Promise.prototype.catch = function (onRejected) {

var handler = {}
if (typeof onRejected === "function") {
    handler.reject = onRejected
}
this.handlerQueue.push(handler)
return this
}

//------ test-------//
function asyncDosomeing(flag, name) {
    const deferred = new Deferred()
    setTimeout(function () {
        if (flag) {
            deferred.resolve({code: 200, message: "成功", name: name})
        } else {
            deferred.reject({code: 400, message: "失敗", name: name})
        }
    }, 2000)
    return deferred.promise
}
asyncDosomeing(true, "asyncDosomeing1").then(result => {
    console.info(result)
    return asyncDosomeing(false, "asyncDosomeing2")
}).then(result => {
    console.info(result)
    return "dadds"
}).then(result => {
    console.info(result)
}).catch(err => {
    console.info("catch")
    console.info(err)
    return asyncDosomeing(true, "asyncDosomeing3----catch")
})

這樣就可以實(shí)現(xiàn),只要異步操作流程中有一步被拒絕,下面流程就自然中斷,直接到catch回調(diào)中處理異常。

六、API Promise化

在編碼的時(shí)候,想要用promise進(jìn)行異步操作流程控制,就要將當(dāng)前的異步回調(diào)函數(shù)封裝成promise。在自己開發(fā)的時(shí)候,往往會去引用第三方的模塊,然后發(fā)現(xiàn)這些模塊的異步回調(diào)API 不支持promise寫法。難道我們自己全部封裝實(shí)現(xiàn)一遍?!這明顯是不合理的。那我們就可以實(shí)現(xiàn)一個(gè) 方法可以批量將方法Promise化,相關(guān)代碼如下:

1.在deferred原型上實(shí)現(xiàn)一個(gè)異步回調(diào)函數(shù),回調(diào)執(zhí)行后觸發(fā)deferred resolve 和 reject的方法

Deferred.prototype.callBack = function () {
    var that = this
    return function (err, result) {
        if (err) {
            that.reject(err)
        } else {
            that.resolve(result)
        }
    }
}

2.定義一個(gè)Api Promise化 方法

/**
 * 將異步操作轉(zhuǎn)換成promise
 */
var promisify = function (method) {
    if (typeof method !== "function") {
        throw new TypeError("is not a function")
    }
    return function () {
        const defrred = new Deferred()
        var args = Array.prototype.slice.call(arguments, 0) // 克隆參數(shù)
        args.push(defrred.callBack())
        method.apply(this, args)
        return defrred.promise
    }
}

最后我們就可以簡化代碼

var readFile = promisify(fs.readFile);
readFile("file.text").then(function(file){
    return readFile(file.trim())
}).then(function(file2){
    console.log(file2)
})

這里只是對promise/deferred 原理的簡單實(shí)現(xiàn),還有很多情況沒有考慮。希望大家在做promise異步流程操作的時(shí)候,還是選擇現(xiàn)在成熟的模塊。比如 q模塊、bulebird、when、或者 es6 的promise 去做。

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

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

相關(guān)文章

  • Node_深入淺出Node

    摘要:簡介項(xiàng)目命名為就是一個(gè)服務(wù)器單純開發(fā)一個(gè)服務(wù)器的想法,變成構(gòu)建網(wǎng)絡(luò)應(yīng)用的一個(gè)基本框架發(fā)展為一個(gè)強(qiáng)制不共享任何資源的單線程,單進(jìn)程系統(tǒng)。單線程弱點(diǎn)無法利用多核錯(cuò)誤會引起整個(gè)應(yīng)用退出,應(yīng)用的健壯性大量計(jì)算占用導(dǎo)致無法繼續(xù)調(diào)用異步。 NodeJs簡介 Ryan Dahl項(xiàng)目命名為:web.js 就是一個(gè)Web服務(wù)器.單純開發(fā)一個(gè)Web服務(wù)器的想法,變成構(gòu)建網(wǎng)絡(luò)應(yīng)用的一個(gè)基本框架.Node發(fā)展...

    shinezejian 評論0 收藏0
  • 讀Zepto源碼之Deferred模塊

    摘要:為的項(xiàng),取出來的分別為和,所以上的和方法,調(diào)用的是中的方法,實(shí)質(zhì)是往各自的回調(diào)列表中添加回調(diào)函數(shù)。進(jìn)度回調(diào)函數(shù)數(shù)組。參數(shù)為異步對象的索引值,參數(shù)為對應(yīng)的上下文數(shù)組,即或,為對應(yīng)的回調(diào)函數(shù)數(shù)組,即或。 Deferred 模塊也不是必備的模塊,但是 ajax 模塊中,要用到 promise 風(fēng)格,必需引入 Deferred 模塊。Deferred 也用到了上一篇文章《讀Zepto源碼之C...

    yagami 評論0 收藏0
  • promise學(xué)習(xí)(2)

    摘要:所謂的能對狀態(tài)進(jìn)行操作的特權(quán)方法,指的就是能對對象的狀態(tài)進(jìn)行等調(diào)用的方法,而通常的的話只能在通過構(gòu)造函數(shù)傳遞的方法之內(nèi)對對象的狀態(tài)進(jìn)行操作。一般會在構(gòu)造函數(shù)中編寫邏輯,什么時(shí)候執(zhí)行回調(diào),什么時(shí)候執(zhí)行回調(diào)。 原文地址 1. 在then中使用reject 如果一個(gè)promise最初只定義了resolve,但是還想要使用reject怎么辦? 可以在then中返回一個(gè)新的promise。這個(gè)...

    firim 評論0 收藏0
  • Node.js 異步異聞錄

    摘要:的異步完成整個(gè)異步環(huán)節(jié)的有事件循環(huán)觀察者請求對象以及線程池。執(zhí)行回調(diào)組裝好請求對象送入線程池等待執(zhí)行,實(shí)際上是完成了異步的第一部分,回調(diào)通知是第二部分。異步編程是首個(gè)將異步大規(guī)模帶到應(yīng)用層面的平臺。 showImg(https://segmentfault.com/img/remote/1460000011303472); 本文首發(fā)在個(gè)人博客:http://muyunyun.cn/po...

    zzbo 評論0 收藏0
  • 再談Promise

    摘要:方法完成回調(diào)注冊模式下,對象通過方法調(diào)用,注冊完成態(tài)和失敗態(tài)的回調(diào)函數(shù)。這些回調(diào)函數(shù)組成一個(gè)回調(diào)隊(duì)列,處理的值。調(diào)用實(shí)例的方法,能使注冊的回調(diào)隊(duì)列中的回調(diào)函數(shù)依次執(zhí)行。 之前寫了一篇關(guān)于ES6原生Promise的文章。近期又讀樸靈的《深入淺出Node》,里面介紹了一個(gè)Promise/Deferred模式。 Promise是解決異步問題的利器。它其實(shí)是一種模式。Promise有三種狀態(tài),...

    chenjiang3 評論0 收藏0

發(fā)表評論

0條評論

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