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

資訊專欄INFORMATION COLUMN

Promise介紹--Deferred及jQuery篇

Darkgel / 1461人閱讀

摘要:我們稱為回調(diào)對(duì)象,它內(nèi)部會(huì)維護(hù)一個(gè)數(shù)組,我們可以向其中添加若干個(gè)回調(diào)函數(shù),然后在某一條件下觸發(fā)執(zhí)行。第一次之后,再次新的回調(diào)函數(shù)時(shí),自動(dòng)執(zhí)行回調(diào)。當(dāng)前面的回調(diào)函數(shù)返回時(shí),終止后面的回調(diào)繼續(xù)執(zhí)行。

最近懶癌發(fā)作,說好的系列文章,寫了一半,一直懶得寫,今天補(bǔ)上一篇。

Deferred

我們?cè)谑褂?b>promise對(duì)象時(shí),總會(huì)提到一個(gè)與它關(guān)系密切的對(duì)象——Deferred。其實(shí)Deferred沒什么內(nèi)容可講的,其實(shí)很簡(jiǎn)單。

它包含一個(gè)promise對(duì)象

它可以改變對(duì)應(yīng)的promise的狀態(tài)

簡(jiǎn)單的實(shí)現(xiàn)如下:

class Deferred{
    constructor(){
        let defer = {};
        defer.promise = new Promise((resolve, reject)=>{
            defer.resolve = resolve;
            defer.reject = reject;
        })
        return defer;
    }
}

我們知道promise對(duì)象內(nèi)部的狀態(tài),本身是在創(chuàng)建對(duì)象時(shí)傳入的函數(shù)內(nèi)控制,外部是訪問不到的,Deferred對(duì)象在它的基礎(chǔ)上包裝了一層,并提供了兩個(gè)在外部改變它狀態(tài)的方法。

用法其實(shí)在Promise介紹--規(guī)范篇中的例子內(nèi),多處使用到了,這里就不再贅述??傆X得文章寫這么點(diǎn)兒,就顯得太水了。。所以借此,講講jQuery中的實(shí)現(xiàn)。

jQuery中還有一個(gè)靜態(tài)方法$.Callbacks(),由于$.Deferred()強(qiáng)依賴它,所以我們先從它開刀。

$.Callbacks()

$.Callbacks()我們稱為回調(diào)對(duì)象,它內(nèi)部會(huì)維護(hù)一個(gè)數(shù)組,我們可以向其中添加若干個(gè)回調(diào)函數(shù),然后在某一條件下觸發(fā)執(zhí)行。

有幾個(gè)方法從名字我們就知道它的作用是什么,add向數(shù)組內(nèi)部添加一個(gè)回調(diào)函數(shù),empty清空數(shù)組,fire觸發(fā)回調(diào)函數(shù),has數(shù)組中是否已經(jīng)添加某回調(diào)函數(shù),remove從數(shù)組中刪除某回調(diào)函數(shù)。

fireWith函數(shù)接收兩個(gè)參數(shù),第一個(gè)是回調(diào)函數(shù)執(zhí)行的上下文,第二個(gè)是回傳給回調(diào)函數(shù)的參數(shù)。fire中其實(shí)內(nèi)部調(diào)用的就是fireWith,其中第一個(gè)參數(shù)傳遞的是this

其它的幾個(gè)函數(shù),都和回調(diào)數(shù)組的狀態(tài)有關(guān)。創(chuàng)建Callbacks對(duì)象時(shí),接收一個(gè)字符串或者對(duì)象作為參數(shù)。其實(shí)內(nèi)部都會(huì)轉(zhuǎn)換為對(duì)象,這里不贅述,不同字符串表示不同的處理方式,一一介紹。

once :對(duì)象只會(huì)調(diào)用一次。

let cb = $.Callbacks("once")
function a(){console.log("a")}
function b(){console.log("b")}
cb.add(a)
cb.fire()
cb.add(b)
cb.fire()
// a

第一次fire之后,回調(diào)列表之后不會(huì)再次觸發(fā)。

memory : 記住回調(diào)列表的執(zhí)行狀態(tài),如果回調(diào)函數(shù)fire過一次,之后每次add之后,則自動(dòng)觸發(fā)該回調(diào)。

let cb = $.Callbacks("memory")
function a(){console.log("a")}
function b(){console.log("b")}
cb.add(a)
cb.fire()
// a
cb.add(b)
// b

第一次fire之后,再次add新的回調(diào)函數(shù)b時(shí),自動(dòng)執(zhí)行回調(diào)b

unique:每一個(gè)回調(diào)函數(shù)只可以添加一次。

let cb = $.Callbacks("unique")
function a(){console.log("a")}
function b(){console.log("b")}
cb.add(a)
cb.add(a)
cb.fire()
// a
cb.add(b)
cb.fire()
// a
// b

第一次fire時(shí),只會(huì)打印一個(gè)a,說明第二個(gè)a沒有添加成功,但當(dāng)我們添加b時(shí),是可以添加成功的。

stopOnFalse:當(dāng)前面的回調(diào)函數(shù)返回false時(shí),終止后面的回調(diào)繼續(xù)執(zhí)行。

let cb = $.Callbacks("stopOnFalse")
function a(){console.log("a");return false;}
function b(){console.log("b")}
cb.add(a)
cb.add(b)
cb.fire()
// a

函數(shù)a返回了false,導(dǎo)致函數(shù)b沒有執(zhí)行。

我們?cè)倩剡^頭看$.Callbacks()對(duì)象的方法,lock方法表示鎖住回調(diào)數(shù)組,不再執(zhí)行,也就是模式為once時(shí),調(diào)用一次fire后的狀態(tài),即在此之后不可以在此觸發(fā)。如下:

let cb = $.Callbacks()
function a(){console.log("a")}
function b(){console.log("b")}
cb.add(a)
cb.fire()
cb.lock()
cb.add(b)
cb.fire()

lock之后,再次添加函數(shù)b并調(diào)用fire時(shí),不會(huì)再次執(zhí)行,與once模式下效果類似。但如果是memory模式,回調(diào)先fire,然后再lock,之后再次add時(shí),新添加的函數(shù)依然會(huì)執(zhí)行。

let cb = $.Callbacks("memory")
function a(){console.log("a")}
function b(){console.log("b")}
cb.add(a)
cb.fire()
cb.lock()
cb.add(b)
// a
// b

其實(shí)這種效果和直接創(chuàng)建回調(diào)對(duì)象時(shí),參數(shù)設(shè)為once memory是一致的。也就是說,如下代碼與上面效果一致。

let cb = $.Callbacks("once memory")
function a(){console.log("a")}
function b(){console.log("b")}
cb.add(a)
cb.fire()
cb.add(b)
// a
// b

我們發(fā)現(xiàn)這種once memory模式,正好與Promisethen方法添加的回調(diào)很類似。如果promise對(duì)象處于pending狀態(tài),則then方法添加的回調(diào)存儲(chǔ)在一個(gè)數(shù)組中,當(dāng)promise對(duì)象狀態(tài)改變(fire)時(shí),執(zhí)行相應(yīng)的回調(diào),且之后再次通過then方法添加回調(diào)函數(shù),新回調(diào)會(huì)立刻執(zhí)行。同時(shí),每一個(gè)回調(diào)只能執(zhí)行一次。所以,$.Deferred()內(nèi)部用的正好是once memoryCallbacks。

還有一個(gè)函數(shù)叫做disable,它的作用是直接禁用掉這個(gè)回調(diào)對(duì)象,清空回調(diào)數(shù)組,禁掉fire、add等。

locked用于判斷數(shù)組是否被鎖住,返回truefalse。disabled用于判斷回調(diào)對(duì)象是否被警用,同樣返回truefalse。

$.Deferred()

有了以上的基礎(chǔ),我們接下來看看jQuery中,Deferred對(duì)象的實(shí)現(xiàn)。我們先看看它都有哪些方法。如圖:

別的方法我們暫且不關(guān)注,我們注意到里面有四個(gè)我們比較熟悉的方法,promise,reject,resolve。它們和我們前面說的Deferred對(duì)象中作用差不多。

jQueryDeferred中有三個(gè)添加回調(diào)函數(shù)的方法done,failprogress,分別對(duì)應(yīng)添加promise狀態(tài)為resolvedrejectedpending時(shí)的回調(diào),同時(shí)對(duì)應(yīng)有三個(gè)觸發(fā)回調(diào)函數(shù)的方法resolverejectnotify。

我們接下來看看它內(nèi)部是怎么實(shí)現(xiàn)的。首先為每種狀態(tài)分別創(chuàng)建一個(gè)Callbacks對(duì)象,如下:

  var tuples = [
      // action, add listener, listener list, final state
     ["resolve", "done", jQuery.Callbacks("once memory"), "resolved"],
     ["reject", "fail", jQuery.Callbacks("once memory"), "rejected"],
     ["notify", "progress", jQuery.Callbacks("memory")]
]

我們發(fā)現(xiàn)donefail對(duì)應(yīng)的回調(diào)對(duì)象是once memory,而progress對(duì)應(yīng)的是memory。說明通過progress添加的函數(shù),可以多次重復(fù)調(diào)用。

然后定義了一個(gè)state用來保存狀態(tài),以及內(nèi)部的一個(gè)promise對(duì)象。

state = "pending",
promise = {
    state: function() {
        return state;
    },
    always: function() {
        deferred.done(arguments).fail(arguments);
        return this;
    },
    then: function( /* fnDone, fnFail, fnProgress */ ) {
    },

    // Get a promise for this deferred
    // If obj is provided, the promise aspect is added to the object
    promise: function(obj) {
        return obj != null ? jQuery.extend(obj, promise) : promise;
    }
},

接下來會(huì)執(zhí)行一個(gè)循環(huán),如下:

// Add list-specific methods
jQuery.each(tuples, function(i, tuple) {
    var list = tuple[2],
        stateString = tuple[3];

    // promise[ done | fail | progress ] = list.add
    promise[tuple[1]] = list.add;

    // Handle state
    if (stateString) {
        list.add(function() {

            // state = [ resolved | rejected ]
            state = stateString;

            // [ reject_list | resolve_list ].disable; progress_list.lock
        }, tuples[i ^ 1][4].disable, tuples[2][5].lock);
    }

    // deferred[ resolve | reject | notify ]
    deferred[tuple[0]] = function() {
        deferred[tuple[0] + "With"](this === deferred ? promise : this, arguments);
        return this;
    };
    deferred[tuple[0] + "With"] = list.fireWith;
});

這一段代碼中我們可以看出,done、failprogress其實(shí)就是add,resolve、rejectnotify其實(shí)就是fire,與之對(duì)應(yīng)的resolveWith、rejectWithnotifyWith其實(shí)就是fireWith。且成功和失敗的回調(diào)數(shù)組中,會(huì)預(yù)先添加一個(gè)函數(shù),用來設(shè)置promise的狀態(tài)和禁用掉其它狀態(tài)下的回調(diào)對(duì)象。

從上面這段代碼中我們也可以看出,添加回調(diào)函數(shù)的方法,都是添加在promise對(duì)象上的,而觸發(fā)回調(diào)的方法是添加在deferred對(duì)象上的。代碼中會(huì)通過如下方法,把promise對(duì)象的方法合并到deferred對(duì)象上。

promise.promise(deferred);

所以,我們打印一下$.Deferred().promise()。

發(fā)現(xiàn)它確實(shí)比$.Deferred()少了那幾個(gè)觸發(fā)回調(diào)的方法。

其它的幾個(gè)方法我們簡(jiǎn)單說一下,always會(huì)同時(shí)在成功和失敗的回調(diào)數(shù)組中添加方法。state是查看當(dāng)前promise對(duì)象的狀態(tài)。

then方法如下:

then: function( /* fnDone, fnFail, fnProgress */ ) {
    var fns = arguments;
    return jQuery.Deferred(function(newDefer) {
        jQuery.each(tuples, function(i, tuple) {
            var fn = jQuery.isFunction(fns[i]) && fns[i];

            // deferred[ done | fail | progress ] for forwarding actions to newDefer
            deferred[tuple[1]](function() {
                var returned = fn && fn.apply(this, arguments);
                if (returned && jQuery.isFunction(returned.promise)) {
                    returned.promise()
                        .progress(newDefer.notify)
                        .done(newDefer.resolve)
                        .fail(newDefer.reject);
                } else {
                    newDefer[tuple[0] + "With"](
                        this === promise ? newDefer.promise() : this,
                        fn ? [returned] : arguments
                    );
                }
            });
        });
        fns = null;
    }).promise();
}

從代碼中我們可以看出,then方法和規(guī)范中的then方法類似,不過這里多了第三個(gè)參數(shù),是用于給progress添加回調(diào)函數(shù),同時(shí)返回一個(gè)新的promise對(duì)象。

pipe是為了向前兼容,它與then是相等的。

$.when()

jQuery中還有一個(gè)與之相關(guān)的方法$.when(),它的作用類似于Promise.all()。具體實(shí)現(xiàn)方式基本是新建了一個(gè)Deferred對(duì)象,然后遍歷所有傳遞進(jìn)去的promise對(duì)象。不過添加了progres
的處理??傊鸵?guī)范有很多的不同,大家有興趣的就自己看一下吧。

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

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

相關(guān)文章

  • jQuery Deferred

    摘要:比較下和也就是說返回值是的一個(gè)非狀態(tài)操作的子集,允許我們添加回調(diào),但是不允許我們操作的狀態(tài)。前面說了的返回值是一個(gè)新的對(duì)象,如果在新的對(duì)象上繼續(xù)添加回調(diào)會(huì)怎么樣呢我們分兩種情況來看。方法的返回值不是對(duì)象的返回值會(huì)傳遞給的參數(shù)。 前言 Deferred是從1.5版本引入的一個(gè)核心特性之一,主要是為了解決Callback Hell,老生常談的問題,這里就不多贅述了。本文旨在剖析Deferr...

    HollisChuang 評(píng)論0 收藏0
  • jquery ajax 方法封裝說明

    摘要:簡(jiǎn)要說明前面我寫了一篇方法封裝及文件設(shè)計(jì)文檔,主要用來說明我們?cè)陧?xiàng)目中通常會(huì)對(duì)的方法進(jìn)行進(jìn)一步的封裝處理,便于我們?cè)跇I(yè)務(wù)代碼中使用。這篇文檔我們主要對(duì)封裝的方法進(jìn)行一個(gè)簡(jiǎn)要說明。 簡(jiǎn)要說明 前面我寫了一篇《jquery ajax 方法封裝及 api 文件設(shè)計(jì)》文檔,主要用來說明我們?cè)陧?xiàng)目中通常會(huì)對(duì) jquery 的 ajax 方法進(jìn)行進(jìn)一步的封裝處理,便于我們?cè)跇I(yè)務(wù)代碼中使用。從那篇文...

    z2xy 評(píng)論0 收藏0
  • jQuery源碼解析Deferred異步對(duì)象

    摘要:回調(diào)隊(duì)列對(duì)象,用于構(gòu)建易于操作的回調(diào)函數(shù)集合,在操作完成后進(jìn)行執(zhí)行。對(duì)象對(duì)象,用于管理回調(diào)函數(shù)的多用途列表。如果傳入一個(gè)延遲對(duì)象,則返回該對(duì)象的對(duì)象,可以繼續(xù)綁定其余回調(diào),在執(zhí)行結(jié)束狀態(tài)之后也同時(shí)調(diào)用其回調(diào)函數(shù)。 在工作中我們可能會(huì)把jQuery選擇做自己項(xiàng)目的基礎(chǔ)庫,因?yàn)槠涮峁┝撕?jiǎn)便的DOM選擇器以及封裝了很多實(shí)用的方法,比如$.ajax(),它使得我們不用操作xhr和xdr對(duì)象,直...

    Coding01 評(píng)論0 收藏0
  • jQuery Deferred對(duì)象

    摘要:給普通的操作指定回調(diào)函數(shù)對(duì)象的最大優(yōu)點(diǎn),就是它把這一套回調(diào)函數(shù)接口,從操作擴(kuò)展到了所有操作。方法用于指定對(duì)象狀態(tài)為已失敗時(shí)的回調(diào)函數(shù)。執(zhí)行完畢執(zhí)行成功執(zhí)行失敗接收一個(gè)或多個(gè)對(duì)象作為參數(shù),為其指定回調(diào)函數(shù)。 什么是deferred對(duì)象 開發(fā)網(wǎng)站的過程中,我們經(jīng)常遇到某些耗時(shí)很長(zhǎng)的javascript操作。其中,既有異步的操作(比如ajax讀取服務(wù)器數(shù)據(jù)),也有同步的操作(比如遍歷一個(gè)大型...

    baoxl 評(píng)論0 收藏0
  • 異步 JavaScript 與 Promise

    摘要:為這些回調(diào)函數(shù)分別命名并分離存放可以在形式上減少嵌套,使代碼清晰,但仍然不能解決問題。如果在一個(gè)結(jié)束成功或失敗,同前面的說明后,添加針對(duì)成功或失敗的回調(diào),則回調(diào)函數(shù)會(huì)立即執(zhí)行。 異步? 我在很多地方都看到過異步(Asynchronous)這個(gè)詞,但在我還不是很理解這個(gè)概念的時(shí)候,卻發(fā)現(xiàn)自己常常會(huì)被當(dāng)做已經(jīng)很清楚(* ̄? ̄)。 如果你也有類似的情況,沒關(guān)系,搜索一下這個(gè)詞,就可以得到大致...

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

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

0條評(píng)論

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