麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁(yè) > 網(wǎng)站 > WEB開(kāi)發(fā) > 正文

jQuery源碼學(xué)習(xí):Deferred Object

2024-04-27 15:14:45
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

本文所有討論均基于jQuery版本3.1.1,官網(wǎng)http://jquery.com/。

一.Deferred Object

1. 簡(jiǎn)介和創(chuàng)建

詳見(jiàn)API:http://api.jquery.com/jQuery.Deferred/。jQuery Deferred是”based onCommonJS PRomises/A design”,并不完全等同于ES6的Promise或者瀏覽器/JS引擎實(shí)現(xiàn)的原生Promise或是各類(lèi)Promise庫(kù)。

jQuery.Deferred()工廠(chǎng)函數(shù)創(chuàng)建一個(gè)新的deferred object并且返回這個(gè)deferred:

jQuery.extend({    Deferred: function (func) {        var deferred = {};              // ...             // 實(shí)現(xiàn)deferred object的對(duì)象方法             // ...         return deferred;    }})

2. deferred與閉包

由于dererred的每個(gè)對(duì)象方法method都訪(fǎng)問(wèn)了外部函數(shù)jQuery.Deferred()中的局部變量,因此jQuery.Deferred()在執(zhí)行完畢后,其活動(dòng)對(duì)象activation object不會(huì)被銷(xiāo)毀,而是被保存在deferred的每個(gè)method的[[Scope]]屬性中(僅保存指針)。這樣deferred的method在執(zhí)行時(shí)就可以通過(guò)作用域鏈scope chain訪(fǎng)問(wèn)到deferred的“私有變量”(參見(jiàn)javascript高級(jí)程序設(shè)計(jì)第三版7.4章)。

這里的“私有變量”不是靜態(tài)的,即每次通過(guò)調(diào)用jQuery.Deferred()得到的deferred都有自己的一份“私有變量”。

注1:這是在jQuery“塊級(jí)作用域”(參見(jiàn)Javascript高級(jí)程序設(shè)計(jì)第三版7.3章)里定義的局部變量:

var%20%20%20%20version%20=%20"3.1.1",%20%20%20%20//%20Define%20a%20local%20copy%20of%20jQuery%20%20%20%20jQuery%20=%20function%20(selector,%20context)%20{...},

注2:這是在jQuery“塊級(jí)作用域”里,通過(guò)下面的語(yǔ)句expose到全局環(huán)境下的變量:

%20%20%20%20window.jQuery%20=%20window.$%20=%20jQuery;

注3:jQuery.Deferred()返回的deferred%20object是jQuery.Deferred()的一個(gè)局部變量。

注4:deferred.promise()返回這個(gè)promise%20object。

3.%20deferred的私有變量

3.1.%20state

取三種值”pending”,”resolved”,”rejected”之一,分別對(duì)應(yīng)Spec里的%20pending,fulfilled,%20or%20rejected;

可以通過(guò).state()方法讀取;

初始狀態(tài)是”pendinig”。

3.2%20promise

可以通過(guò).promise()讀取。和deferred一樣是jQuery.Deferred()的局部變量:

var%20promise%20=%20{%20%20%20%20...%20%20%20%20promise:%20function%20(obj)%20{%20%20%20%20%20%20%20%20return%20obj%20!=%20null%20?%20jQuery.extend(obj,%20promise)%20:%20promise;%20%20%20%20}},%20%20%20%20deferred%20=%20{};%20%20%20%20…%20%20%20//%20向deferred添加resolve,reject,notify,resolveWith,rejectWith和notifyWith方法%20%20%20%20//%20Make%20the%20deferred%20a%20promise%20%20%20%20promise.promise(deferred);

從上面jQuery.Deferred()的代碼可以看出,deferred對(duì)象copy了promise所有的方法;deferred和promise的方法指向相同的函數(shù)實(shí)例,因而deferred和deferred.promise()擁有同一份“私有變量”:

promise沒(méi)有可以改變state的方法,即promise沒(méi)有.resolve()/.resolveWith()/.reject()/.rejectWith()/.notify()/.notifyWith()方法。這樣返回deferred.promise()給其它代碼就可以確保其它代碼不會(huì)改變deferred的狀態(tài)或觸發(fā)回調(diào)函數(shù)的執(zhí)行。

3.3%20tuples

var%20tuples%20=%20[%20%20%20%20%20%20%20%20//%20action,%20add%20listener,%20callbacks,%20%20%20%20%20%20%20%20//%20...%20.then%20handlers,%20argument%20index,%20[final%20state]%20%20%20%20%20%20%20%20["notify",%20"progress",%20jQuery.Callbacks("memory"),%20%20%20%20%20%20%20%20%20%20%20%20jQuery.Callbacks("memory"),%202],%20%20%20%20%20%20%20%20["resolve",%20"done",%20jQuery.Callbacks("once%20memory"),%20%20%20%20%20%20%20%20%20%20%20%20jQuery.Callbacks("once%20memory"),%200,%20"resolved"],%20%20%20%20%20%20%20%20["reject",%20"fail",%20jQuery.Callbacks("once%20memory"),%20%20%20%20%20%20%20%20%20%20%20%20jQuery.Callbacks("once%20memory"),%201,%20"rejected"]%20%20%20%20],

tuples數(shù)組存放了6個(gè)callback%20list%20object,為討論方便,我們命名

 %20 %20progress_callbacks%20= tuples[0][2],%20 %20progress_handlers%20= tuples[0][3]

 %20 %20fulfilled_callbacks%20= tuples[1][2],%20 %20 %20 %20fulfilled_handlers%20= tuples[1][3]

 %20 %20rejected_callbacks%20= tuples[2][2],%20 %20 %20rejected_handlers%20= tuples[2][3]

3.3.1%20callback%20list

以fulfilled_callbacks即tuples[1][2]為例,它是由jQuery.Callbacks(“once%20memory”)創(chuàng)建的一個(gè)callback%20list,這個(gè)callbacklist的.add()方法把回調(diào)函數(shù)加入到list中,而.fireWith()方法將導(dǎo)致list里的所有回調(diào)函數(shù)以類(lèi)似于”先進(jìn)先出”的順序執(zhí)行。

3.3.2%20“once”%20flag

fulfilled_callbacks創(chuàng)建時(shí)帶有兩個(gè)flag:”once”和”memory”?!皁nce”表示這個(gè)callback%20list只能通過(guò).fireWith()或.fire()的調(diào)用被fire一次,以后再次調(diào)用這個(gè)callback%20list的.fireWith()或.fire()沒(méi)有任何效果。

注意progress_callbacks和progress_handlers創(chuàng)建時(shí)沒(méi)有”once”這個(gè)flag,也就是說(shuō)這兩個(gè)callback%20list可以被多次fire,每次fire時(shí)list里的所有回調(diào)函數(shù)順序執(zhí)行。

3.3.3%20“memory”%20flag

callback%20list在fire時(shí)的context和arguments將被“記憶”下來(lái),這樣在.fireWith()之后調(diào)用.add()的話(huà),新加入的回調(diào)函數(shù)將馬上用“記住”的context和arguments執(zhí)行。

%20%20%20%20fulfilled_callbacks%20=%20jQuery.Callbacks("once%20memory");%20%20%20%20fulfilled_callbacks.add(fn1);%20%20%20%20fulfilled_callbacks.add(fn2);%20%20%20%20fulfilled_callbacks.fireWith(context,%20args);%20%20%20//%20fn1先執(zhí)行,即fn1.apply(context,args);然后fn2執(zhí)行fn2.apply(context,args)%20 %20%20%20%20fulfilled_callbacks.fireWith(context,%20args);%20%20%20//%20沒(méi)有任何效果%20%20%20%20fulfilled_callbacks.add(fn3);%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20fn3馬上執(zhí)行,即fn3.apply(context,%20args)

3.4.%20對(duì)象方法與私有變量

Deferred的對(duì)象方法

這個(gè)方法會(huì)調(diào)用

對(duì)狀態(tài)的影響

效果

.done()

fulfilled_callbacks.add()

不改變state

把回調(diào)函數(shù)加入到fulfilled_callbacks中

.resolve()/.resolveWith()

fulfilled_callbacks.fireWith()

state%20=%20“resovled”

fulfilled_callbacks中的所有回調(diào)函數(shù)被執(zhí)行注1

fulfilled_handlers中的所有回調(diào)函數(shù)被執(zhí)行

.fail()

rejected_callbacks.add()

不改變state

把回調(diào)函數(shù)加入到rejected_callbacks中

.reject()/.rejectWith()

rejected_callbacks.fireWith()

state%20=%20“rejected”

rejected_callbacks中的所有回調(diào)函數(shù)被執(zhí)行注1

rejected_handlers中的所有回調(diào)函數(shù)被執(zhí)行

.progress()

progress_callbacks.add()

不改變state

把回調(diào)函數(shù)加入到progress_callbacks中

.notify()/.notifyWith()

progress_callbacks.fireWith()

不改變state

progress_callbacks中的所有回調(diào)函數(shù)被執(zhí)行

progress_handlers中的所有回調(diào)函數(shù)被執(zhí)行

.then()/.catch()

fulfilled_handlers.add()

rejected_handlers.add()

progress_handlers.add()

不改變state

把回調(diào)函數(shù)加入到fulfilled_handlers中

把回調(diào)函數(shù)加入到rejected_handlers中

把回調(diào)函數(shù)加入到progress_handlers中

注1:這兩個(gè)方法如果重復(fù)執(zhí)行的話(huà),只有第一次的調(diào)用會(huì)有效果,原因見(jiàn)3.3.2。

4.%20鏈?zhǔn)秸{(diào)用

除了.state()和.promise()外,deferred的其它方法均返回一個(gè)deferred%20object,這樣deferred就可以支持鏈?zhǔn)秸{(diào)用,例如.always():

always:%20function%20()%20{%20%20%20%20deferred.done(arguments).fail(arguments);%20%20%20%20return%20this;},

調(diào)用.always()方法相當(dāng)于同時(shí)向fulfilled_callbacks和rejected_callbacks中添加了一個(gè)同樣的回調(diào)函數(shù),這樣無(wú)論這個(gè)deferred是被.resolve()/.resolveWith()還是.reject()/.rejectWith(),這個(gè)回調(diào)函數(shù)always將被執(zhí)行。

需要注意的是大多數(shù)方法均返回this指針,也就是方法在哪個(gè)deferred上被調(diào)用,就返回哪個(gè)deferred。而.then()和.catch()方法返回的是一個(gè)新的deferred的promise。

%20%20%20%20dfd1%20=%20jQuery.Deferred();%20%20%20%20dfd1.done(fn)%20===%20dfd1;%20%20%20%20%20%20%20%20%20%20%20%20//true%20%20%20%20dfd1.then(fn)%20===%20dfd1.promise();%20//false

二.Control%20Flow

1.%20同步執(zhí)行流程

這里的同步執(zhí)行流程指的是在同一個(gè)event%20loop里被順序執(zhí)行的代碼。由于是在一個(gè)event%20loop里單線(xiàn)程運(yùn)行,這些代碼是同步執(zhí)行的。例如deferred.resolve()/.resolveWith()被調(diào)用時(shí),代碼總是按照下圖中箭頭指定的順序執(zhí)行:

注1:也就是說(shuō),在deferred.resolve()/.resolveWith()之后,再去調(diào)用deferred.reject()/.rejectWith()將沒(méi)有任何效果。反之亦然。

注2:如果.notify()/.notifyWith()被調(diào)用過(guò),那么.resolve()/.resolveWith()調(diào)用時(shí)不會(huì)disable掉progress_callbacks.add(),這樣仍然可以通過(guò)progress()方法加入progress的回調(diào)函數(shù),而且這樣加入的回調(diào)函數(shù)會(huì)被立即執(zhí)行。

    dfd1 = jQuery.Deferred();    dfd1.progress(function () {        console.log("progress1")    });    dfd1.notify();                    // console log "progress1"    dfd1.resolve();    dfd1.progress(function () {      // console log "progress2" immediately, i.e. before dfd1.progress() returns        console.log("progress2")    });

當(dāng)然如果.notify()/.notifyWith()沒(méi)有被調(diào)用過(guò),那么.resolve()/.resolveWith()調(diào)用后就無(wú)法通過(guò).progress()方法加入progress的回調(diào)函數(shù)了。

2. .then()

2.1 .then()同步執(zhí)行流程

jQuery.Deferred()調(diào)用時(shí)可以帶一個(gè)參數(shù),這個(gè)參數(shù)指向一個(gè)函數(shù)func,在jQuery.Deferred()最后返回deferred之前會(huì)調(diào)用這個(gè)函數(shù)func。

Deferred: function (func) {    …    if (func) {        func.call(deferred, deferred);    }    // All done!    return deferred;},

.then()在最終返回新的deferredobject(其實(shí)是promise)之前,就調(diào)用了一個(gè)函數(shù)func:

then: function (onFulfilled, onRejected, onProgress) {          …return jQuery.Deferred(func).promises();}

.then()方法的同步執(zhí)行流程如下:

用文字描述的話(huà),deferred.then(onFulfilled)方法被調(diào)用時(shí)主要完成了兩件“任務(wù)”:

a. 把“包裹”了真正的回調(diào)函數(shù)onFulfilled的一個(gè)函數(shù)加入了deferred的“私有變量”fulfilled_handlers當(dāng)中;

b. 產(chǎn)生了一個(gè)新的deferredobject即newDefer,并最終返回了newDefer.promise()。

當(dāng)然這只是邏輯上的劃分,實(shí)際運(yùn)行時(shí).then()是同步執(zhí)行的:“任務(wù)”b的前半段先執(zhí)行(得到了newDefer),接下來(lái)“任務(wù)”a執(zhí)行(需要newDefer作為實(shí)參),最后“任務(wù)”b的后半段執(zhí)行,就如上圖所示。

2.2 加入到fulfilled_handlers中的函數(shù)

在上圖右側(cè)代碼部分,tuples[1][3]就是fulfilled_handlers,它的.add()方法將這個(gè)方法的參數(shù)加入到fulfilled_handlers中,也就是把執(zhí)行resolve()函數(shù)得到的返回值加入到fulfilled_handlers中。而resolve()函數(shù)返回一個(gè)匿名的內(nèi)部函數(shù),所以,加入到fulfilled_handlers中的函數(shù)是執(zhí)行resolve()函數(shù)返回的(resolve()函數(shù)的)內(nèi)部函數(shù)。

function resolve(depth, deferred, handler, special) {    return function () {            …    };}

請(qǐng)注意這個(gè)resolve()函數(shù)本身是.then()方法的內(nèi)部函數(shù),并不是.resolve()方法。

 

3. 異步執(zhí)行

3.1 異步的觸發(fā)

deferred.resolve()/resolveWith()執(zhí)行時(shí),會(huì)調(diào)用fulfilled_handlers,fire(),從而運(yùn)行已加入到fulfilled_handlers中的函數(shù)。從上一節(jié)可知,此時(shí)運(yùn)行的就是resolve()的內(nèi)部匿名函數(shù),如下:

function () {        var that = this,            args = arguments,            mightThrow = function () {…},            // Only normal processors (resolve) catch and reject exceptions            process = special ?                mightThrow :                function () {                    try {                        mightThrow();                    } catch (e) {…}                  }                };        // Support: Promises/A+ section 2.3.3.3.1        // https://promisesaplus.com/#point-57        // Re-resolve promises immediately to dodge false rejection from        // subsequent errors        if (depth) {            process();        } else {…            window.setTimeout(process);        }    };}

這個(gè)函數(shù)定義了兩個(gè)(對(duì)于它而言的)內(nèi)部函數(shù)process()和mightThrow(),并在最后調(diào)用了window.setTimeout(),這樣process()作為定時(shí)器的回調(diào)函數(shù)被異步執(zhí)行。

3.2 異步執(zhí)行時(shí)的作用域鏈

3.3 process()的執(zhí)行

3.3.1 fulfilled并且onFulfilledhandler返回了non-thenable

這種情況下,process()主要完成了兩個(gè)“任務(wù)”:

a. 運(yùn)行先前.then()調(diào)用中傳入的handler即上圖中的onFulfilled,返回值賦給returned; 

    returned = handler.apply(that, args);

這里handler是.then()調(diào)用中傳入的onFulfilled,that是.resolveWith()時(shí)傳入的context,args是.resolveWith()時(shí)傳入的args,參考上圖。

b. 傳遞狀態(tài),這是通過(guò)執(zhí)行語(yǔ)句deferred.resolveWith(that, args)來(lái)完成的。這里deferred其實(shí)是.then()產(chǎn)生的newDefer,that是.resolveWith()時(shí)傳入的context,args是上一個(gè)任務(wù)中apply onFulfilled的返回returned,參考上圖。

3.3.2 fulfilled而且onFulfilledhandler返回了thenable

這種情況下,第一個(gè)任務(wù)和前一種情況是一樣的:

a. 運(yùn)行先前.then()調(diào)用中傳入的handler即上圖中的onFulfilled,返回值賦給returned;

b. 遞歸。因?yàn)閞eturned不是一個(gè)“可傳遞”的狀態(tài)(而是一個(gè)有著then方法的對(duì)象),無(wú)法直接傳遞給newDefer,只有等到returned這個(gè)thenable產(chǎn)生了一個(gè)狀態(tài),并且這個(gè)狀態(tài)是“可傳遞”的(不是另外一個(gè)thenable),我們才能繼續(xù)狀態(tài)的傳續(xù)給newDefer。

這種情況下,下面的代碼將執(zhí)行:

then.call(    returned,    resolve(maxDepth, deferred, Identity, special),    resolve(maxDepth, deferred, Thrower, special),    resolve(maxDepth, deferred, Identity,        deferred.notifyWith));

這里then是returned.then,deferred就是newDefer,Identify函數(shù)如下:

function Identity(v) {    return v;}

為方便起見(jiàn),我們把上面這個(gè)call()調(diào)用中的第二個(gè)參數(shù)resolve()的返回結(jié)果叫做identity_wrapper_handler,那么上面這個(gè)call()大致等效于(僅考慮fulfilled情況)

    returned.then(identity_wrapper_handler);

step 1. identity_wrapper_handler將被異步調(diào)用,即在process()中會(huì)apply identity_wrapper_handler

step 2. identity_wrapper_handler是調(diào)用resolve(maxDepth, deferred, Identity, special)返回的函數(shù),這里maxDepth=1,deferred就是newDefer,special是undefined,可參考上面的作用域鏈圖。這樣apply identity_wrapper_handler會(huì)導(dǎo)致process()再次被運(yùn)行。

step 3. 但是這次handler是Identity,所以這次process()會(huì)apply Identity,根據(jù)上面Identify函數(shù)的定義,apply Identity將會(huì)返回returned被resolve時(shí)的狀態(tài)。換句話(huà)說(shuō),如果returned.reslove(y),那么apply Identity將會(huì)返回y。

step 4. 這時(shí)我們又回到了類(lèi)似于process()第一次執(zhí)行時(shí)情況:如果y不是一個(gè)thenable,那么狀態(tài)可以傳遞給newDefer;否則就重復(fù)3.3.2.b的“任務(wù)”,這樣就形成了遞歸。

對(duì)照規(guī)范https://promisesaplus.com/來(lái)看,3.3.2.b描述的就是規(guī)范中的”P(pán)romise Resolution Procedure”。如果認(rèn)為deferred就是規(guī)范中的promise,returned就是規(guī)范中的x,returned.reslove(y)里的y就是規(guī)范中的y,那么3.3.2.b就實(shí)現(xiàn)了規(guī)范2.3所描述的從[[Resolve]](promise,x)到[[Resolve]](promise,y)。

從process()調(diào)用來(lái)看,先后發(fā)生了三次process()調(diào)用,每次process()調(diào)用時(shí)變量所指向/引用的對(duì)象如下表:

 

每次process()運(yùn)行都先執(zhí)行語(yǔ)句returned = handler.apply(that, args);

作用域鏈

handler

that

args

第一次運(yùn)行時(shí)

onFulfilled

deferred.resolveWith(context, args)中的context

deferred.resolveWith(context, args)中的args

指向deferred.then()運(yùn)行后形成的closures

第二次運(yùn)行時(shí)

identity_wrapper_handler

returned.resolveWith(context, args)中的context

returned.resolveWith(context, args)中的args

指向returned.then()運(yùn)行后形成的closures

第三次運(yùn)行時(shí)

Identity

returned.resolveWith(context, args)中的context

returned.resolveWith(context, args)中的args

同第一次,即也指向deferred.then()運(yùn)行后形成的closures

實(shí)現(xiàn)中還有一些細(xì)節(jié),比如防止self thenable resolution,在follow thenable時(shí)避免false rejections,遵從協(xié)議的細(xì)節(jié)處理exceptions等等。

三.Deferred的應(yīng)用

比如jQuery中ready方法還有Ajax等等都用到了deferred object。


發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 国产精品一区自拍 | 欧美大电影免费观看 | 国产午夜精品久久久久久久蜜臀 | 美女久久| 久久国产精品电影 | 欧美一级黄色免费 | 性生活视频一级 | 国产精品资源手机在线播放 | 黄色网址你懂的 | 亚洲3atv精品一区二区三区 | 国产成人精品免费视频大全办公室 | 少妇一级淫片免费放播放 | 日韩视频在线不卡 | 激情97 | 一级黄色毛片子 | 欧美成人二区 | 国产精品亚洲yourport | 欧美成人一区二区三区 | 91久久精品一区二区 | 哪里可以看免费的av | 国产成人自拍视频在线 | 一级黄色播放 | 性生活香蕉视频 | 免费在线观看午夜视频 | 激情亚洲网 | chinesegv男男猛男无套 | 国产妇女乱码一区二区三区 | 国产午夜亚洲精品理论片大丰影院 | 亚洲第一激情 | 欧美日本一 | 黄色aaa视频 | 国产精品视频亚洲 | 亚洲第一精品在线 | 欧美一级毛片欧美一级成人毛片 | 性爱免费在线视频 | 免费观看一级黄色片 | 免费一级片网站 | 黄色av网站免费看 | 亚洲成人入口 | 久久久久久久久淑女av国产精品 | 天天看成人免费毛片视频 |