日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入解析jQuery中的延时对象的概念

發布時間:2023/12/2 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入解析jQuery中的延时对象的概念 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
首先我們需要明白延時對象有什么用?

第一個作用,解決時序以及動態添加執行函數的問題。

function a(){alert(1)}; function b(){alert(2)}; function c(){alert(3)}; a(); setTimeout(function(){b();},0); c();

很明顯函數執行順序是a->c->b,而不是按照函數添加的順序執行。如果我要保證函數按順序執行,那么c 必須寫緊跟在b后面執行

setTimeout(function(){b(); c();},0);

如果添加的函數按順序執行,比如添加在b后面的函數都在b執行后執行(如果b已經執行過了,那么久馬上執行)。如果按照這種方式,我們必須在執行之前就知曉說有要執行的函數,然后都加到setTimeout里面去,這個限制非常可惡。我希望的是即使b執行過了,我后面還能動態的添加函數并得到執行。比如

var defer = $.Deferred(); //構建異步對象
function a(){alert(1)}; function b(){alert(2)};
//添加函數
defer.done(
a);
//添加函數
defer.done(b);setTimeout(function(){
  defer.resolve();//alert(1),alert(2)
},0);
//添加函數
defer.done(function c(){alert(3)});//馬上執行出結果alert(3)

第二,解決參數傳遞的問題,所有的執行函數需要的參數相同,我希望我只傳遞一個參數就將所有的結果執行出來,特別是后續添加的函數執行我也希望使用原來的參數。

function a(value){alert("a = " value)}; function b(value){alert("b = " value)}; var list = [],val = 0;; list[list.length] = a; list[list.length] = b; function runList(listArray,value){for(var i = 0; i < listArray.length; i ){listArray[i](value);}listArray.length = 0; } val = 5; runList(list,val );//執行a = 5;b = 5; list[list.length] = function c(value){alert("c = " value)}; runList(list,val);//執行結果c = 5

在保證runList函數有自己的作用域,不使用外部變量的情況下,那么我們每次執行runList都需要重新傳遞list和val這個變量。這種重復勞動沒有任何意義。看看deferred的處理方式

var defer = $.Deferred(); //構建異步對象 function a(value){alert("a = " value)}; function b(value){alert("b = " value)}; defer.done(a,b);//添加函數 defer.resolve(5);//執行結果a = 5; b = 5; defer.done(function c(value){alert("c = " value)});//添加函數,執行結果c = 5

首先你要承認的是代碼簡化和可讀性都高很多,其次,傳遞的執行參數值5只需要一次便足夠,哪怕是后面添加的函數c也會用先前傳遞過來的參數執行。

Deferred函數將Callbacks函數抽離出去以后Deferred函數變得很精簡。如下

jQuery.extend({Deferred : function(){…}when : function(){…} )}

其中Deferred的整體結構如下

  Deferred: function( func ) {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") ]],state = "pending",promise = {state: function() {…},always: function() {…},then: function( /* fnDone, fnFail, fnProgress */ ) {…},promise: function( obj ) {…}},deferred = {}; //兼容老版本promise.pipe = promise.then; // 添加promise的三個方法[done | fail | progress]方法
    // 添加deferred的六個方法[resolve |resolveWith | reject | rejectWith | notify | notifyWith]
jQuery.each( tuples, function( i, tuple ) {...});    // Make the deferred a promisepromise.promise( deferred );...     return deferred;}

主要做了幾個工作。

  • 定義promise的幾個對外接口state/always/then/promise
  • 通過tuples初始化deferred的幾個接口resolve/resolveWith/reject/rejectWith/notify /notifyWith,并且為promise定義了另外的三個接口done/fail/progress。其中會被添加到這些個接口都與tuples創建的三個Callbacks有關。后續再詳解。
  • 使用promise.promise拓展deferred返回。我們看一下這個返回有哪些個方法  
  • deferred.done(fns)

    將回調添加到成功回調列表(doneCallbacks),當Deferred(延遲)對象解決(調用resolve)時會執行成功回調列表中的所有函數。參數fns可以是函數,也可以是函數數組

    ?deferred.fail(fns)

    ?將回調添加到失敗回調列表(failCallbacks),當Deferred(延遲)對象拒絕(調用reject)時會執行失敗回調列表中的所有函數。參數fns可以是函數,也可以是函數數組

    deferred.always(fns)

    將回調添加到成功回調列表(doneCallbacks和失敗回調列表(failCallbacks)。確保當Deferred(延遲)對象解決(調用resolve)或拒絕(調用reject)時,都會執行到該回調。參數fns可以是函數,也可以是函數數組

    ?

    deferred.progress(fns)

    ?將回調添加到進度回調列表(progressCallbacks),當Deferred(延遲)對象生成進度通知(調用notify)時,執行進度回調列表中的所有函數。參數fns可以是函數,也可以是函數數組

    ?

    deferred.resolve(args)

    ?解決Deferred(延遲)對象,并根據給定的args參數執行成功回調列表(doneCallbacks)的所有函數。

    ?

    deferred.resolveWith(context, args)

    ?解決Deferred(延遲)對象,并根據給定的 context和args參數執行成功回調列表(doneCallbacks)的所有函數。這是jQuery.Callbacks的內部方法fireWith的引用,deferred.resolve()方法內部調用該方法來實現。不建議外部使用。

    ?

    deferred.reject(args)

    ?拒絕Deferred(延遲)對象,并根據給定的args參數調用失敗回調列表(failCallbacks)中的所有函數。

    ?

    deferred.rejectWith(context, args)

    ?拒絕Deferred(延遲)對象,并根據給定的 context和args參數執行失敗回調列表(failCallbacks)的所有函數。這是jQuery.Callbacks的內部方法fireWith的引用,deferred.reject()方法內部調用該方法來實現。不建議外部使用。

    ?

    deferred.notify(args)

    ?根據給定的 args參數 調用Deferred(延遲)對象上進度回調列表(progressCallbacks)的所有函數。

    ?

    deferred.notifyWith(contex,args)

    ?根據給定的上下文(context)和args遞延調用Deferred(延遲)對象上進度回調列表(progressCallbacks )上的所有函數。這是jQuery.Callbacks的內部方法fireWith的引用,deferred.notify()方法內部調用該方法來實現。不建議外部使用。

    ?

    deferred.state()

    ?確定一個Deferred(延遲)對象的當前狀態。"pending"、"resolved"、"rejected"

    ?

    deferred.pipe()/deferred.then()

    ?當Deferred(延遲)對象解決(resolve)、拒絕(reject)或生成進度(notify),調用相應回調列表的所有函數。

    ?

    jQuery.Deferred()

    ??一個構造函數,返回一個延時對象。

    ?

    jQuery.when(subordinate /* , ..., subordinateN */)

    ?提供一種方法來執行一個或多個對象的回調函數, Deferred(延遲)對象通常表示異步事件。

    ?

    .promise()

    ?返回一個 Promise 對象用來觀察當某種類型的所有行動綁定到集合,排隊與否還是已經完成

      

    a. $.Deferred()詳解


    關鍵源碼如下

    Deferred: function( func ){var tuples = [     // 執行名, 添加監聽器(回調), 監聽列表(回調列表), 最終狀態[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],[ "notify", "progress", jQuery.Callbacks("memory") ]],state = "pending",promise = {...promise: function( obj ) {       return obj != null ? jQuery.extend( obj, promise ) : promise;}},deferred = {};   
      //
    添加列表指定的方法   jQuery.each( tuples, function( i, tuple ) {     var list = tuple[ 2 ],stateString = tuple[ 3 ];    // promise[ done | fail | progress ] = list.add     promise[ tuple[1] ] = list.add;    // 只有tuples[0]和tuples[1]進入該分支     if ( stateString ) {       //給Callbacks對象添加回調列表       list.add(function() {         // state = [ resolved | rejected ]         state = stateString;         // [ reject_list | resolve_list ].disable; progress_list.lock       }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].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;});  // 給deferred添加promise的函數接口   promise.promise( deferred );   ...
      return
    deferred; }

    我們把tuples[index][2]中的jQuery.Callbacks返回的對象所代表的回調列表分別取名叫做doneCallbacks(成功回調列表),failCallbacks(失敗回調列表),progressCallbacks(進度回調列表)。則到函數執行到promise.promise( deferred );之前。promise變量變成了

    promise = {state: function() {…},always: function() {…},then: function( /* fnDone, fnFail, fnProgress */ ) {…},promise: function( obj ) {…},done: doneCallbacks.add,fail: failCallbacks.add,progress: progressCallbacks.add }

    deferred變量變成了

    deferred = {resolve: function() {deferred["resolveWith" ]( this === deferred ? promise : this, arguments );return this;},resolveWith: doneCallbacks.fireWith,reject: function() {deferred["rejectWith" ]( this === deferred ? promise : this, arguments );return this;},rejectWith: failCallbacks.fireWith,notify: function() {deferred["notifyWith" ]( this === deferred ? promise : this, arguments );return this;},notifyWith: progressCallbacks.fireWith }

    初始化結束后doneCallbacks中回調隊列如下

    [function(){state = “resolved”:},failCallbacks.disable,progressCallbacks.lock ]

    初始化結束后failCallbacks中回調隊列如下

    [function(){state = “rejected”;},doneCallbacks.disable,progressCallbacks.lock ]

    初始化結束后progressCallbacks的回調列表中沒有任何回調

    需要注意的是doneCallbacks、failCallbacks的設置是”once memory”,progressCallbacks設置是”memory”

    這樣,應當好理解Deferred的原理了。我們使用done/fail是”once memory”設置下的add。意味著如果如果先執行了resolve/ reject方法,后調用done/fail則會直接執行回調。

    eg:

    var defer = $.Deferred(); //構建異步對象
    //執行doneCallbacks的回調,保存場景,這個時候doneCallbacks有三個回調函數,依序執行。其中第二個回//調禁用failCallbacks(禁用reject/rejectWith),第三個回調鎖progressCallbacks(鎖notify/notifyWith) defer.resolve( 5 ); defer.done(function( value ) {console.log('打印出值',value) });//doneCallbacks.add,立刻執行回調

    如果是先調用done/fail,后執行resolve/reject。根據”once memory”將會先添加回調,然后fire。

    eg:

    var defer = $.Deferred(); //構建異步對象 //1秒鐘后執行doneCallbacks回調,保存場景。這個時候的doneCallbacks有四個回調函數,依序執行 setTimeout(function(){defer.resolve( 5 ); },1000); //根據”once memory”,第一次fire之前會把回調添加到doneCallbacks中。等待調用 defer.done(function( value ) {console.log('打印出值',value)});

    當延遲對象被 resolved 時,任何通過 deferred.then或deferred.done 添加的 doneCallbacks,都會被調用。回調函數的執行順序和它們被添加的順序是一樣的。傳遞給 deferred.resolve() 的 args 參數,會傳給每個回調函數。當延遲對象進入 resolved 狀態后,再添加的任何 doneCallbacks,當它們被添加時,就會被立刻執行,并帶上傳入給 .resolve()的參數

    ?b. Deferred.promise.then詳解

    API是這么定義的:

    deferred.then( doneFilter [, failFilter ] [, progressFilter ] )

    從jQuery 1.8開始, 方法返回一個新的promise(承諾),通過一個函數,可以過濾deferred(延遲)的狀態和值。替換現在過時的deferred.pipe()方法。   doneFilter 和 failFilter函數過濾原deferred(延遲)的解決/拒絕的狀態和值。 progressFilter 函數過濾器的任何調用到原有的deferred(延遲)的notify 和 notifyWith的方法。

    這些過濾器函數可以返回一個新的值傳遞給的 promise(承諾)的.done() 或 .fail() 回調,或他們可以返回另一個觀察的對象(遞延,承諾等)傳遞給它的解決/拒絕的狀態和值promise(承諾)的回調。

     

    如果過濾函數是空,或沒有指定,promise(承諾)將得到與原來值相同解決(resolved)或拒絕(rejected)。

    源碼解析:

    then: function( /* fnDone, fnFail, fnProgress */ ) {   var fns = arguments;return jQuery.Deferred(function( newDefer ) {//遍歷tuples,將fnDone, fnFail, fnProgress分別綁定到tuples[0-2][2]的回調列表上jQuery.each( tuples, function( i, tuple ) {var action = tuple[ 0 ],//resolve/reject/notifyfn = jQuery.isFunction( fns[ i ] ) && fns[ i ];       //執行deferred[ done | fail | progress ] 函數,將回調fnDone, fnFail, fnProgress分別添加到回調列表       //需要明確的是這些回調函數是添加到deferred中的,不是newDefer中的。deferred[ tuple[1] ](function() {         //執行fnDone, fnFail, fnProgress函數         var returned = fn && fn.apply( this, arguments );         //如果返回的是Deferred對象或是Deferred.promise對象         if ( returned && jQuery.isFunction( returned.promise ) ) {           //當Deferred(延遲)對象解決/拒絕/生成進度通知時//調用添加處理程續resolve/reject/notifyreturned.promise().done( newDefer.resolve ).fail( newDefer.reject ).progress( newDefer.notify );} else {           //執行resolveWith/rejectWith/notifyWith函數執行所有剩余回調           newDefer[ action "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );}});});fns = null;}).promise(); }。

    我們抓住幾點:

    返回的是新的promise對象

    內部有一個過濾器函數

    我們將最外層初始化的延時對象叫做主延時對象mainDeferred,經過mainDeferred.then()方法處理的代碼中返回的jQuery.Deferred(...).promise(),不是原來的mainDeferred了,我們把它命名為thenDeferred。thenDeferred初始化的時候有這個一段

    // 調用給定的func參數if ( func ) {func.call( deferred, deferred );}

    剛好thenDeferred的初始化帶有函數參數我們命名為thenParamfunc。thenParamfunc的參數是newDefer,結合上面執行func的代碼我們可知,這個newDefer就是thenDeferred嘛,饒了半天。thenParamfunc中做一個操作:

    往mainDeferred的三個回調列表中添加回調,每個回調內部會執行mainDeferred.then添加的對應的回調函數。

          //deferred是主延時對象mainDeferred
          deferred[ tuple[1] ](function() {
            
    //執行fnDone, fnFail, fnProgress函數
            
    var returned = fn && fn.apply( this, arguments );
            
    ...      });

    還需要注意的是當這些回調被調用時,mainDeferred.then添加的回調執行后,會執行下面的代碼

    newDefer[ action "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );

    這表明mainDeferred.then生成的延時對象thenDeferred的狀態依賴于主延時對象mainDeferred。當mainDeferred解決(resolve),那么thenDeferred也會被解決(resolve),并且mainDeferred.then設置的doneFilter的返回值將作為參數傳遞給thenDeferred的回調列表。

    eg:

    var deferred = $.Deferred(); var m = deferred .done(function(val){console.log('done function ' val)}) .then(function(val){console.log('done then ' val); return 10;},   function(val){console.log('fail then ' val);},   function(val){console.log('progress then' val);})  //主延時對象解決
    //打印done function 5;
    done then 5;
    deferred.resolve(5);

    //執行then deferred done 10
    m.done(function(val){console.log("then deferred done " value)})

    現在完整的分析一個例子的數據

    eg:

    var deferred = $.Deferred(); deferred .done(function(val){console.log('done function ' val)}) .then(function(val){console.log('done then' val);},   function(val){console.log('fail then' val);},   function(val){console.log('progress then' val);}) deferred.resolve(5);

    說明:

    deferred.done(...).then(...)執行后,done的回調列表doneCallbacks是下面的樣子

    doneCallbacks = [
      function () {     // state = [ resolved | rejected ]state = stateString;     // [ reject_list | resolve_list ].disable; progress_list.lock},   function () {list = stack = memory = undefined;     return this;},   function () {stack = undefined;     if ( !memory ) {self.disable();}     return this;},   function (val){console.log('done function ' val)},   function () {     var returned = fn && fn.apply( this, arguments );     if ( returned && jQuery.isFunction( returned.promise ) ) {returned.promise().done( newDefer.resolve ).fail( newDefer.reject ).progress( newDefer.notify );} else {newDefer[ action "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );}}
    ]

    其中doneCallbacks前面三個是Callbacks自帶的,第四個是.done添加的,

    第五個這個是.then的第一個參數添加的,對應的fn是function(val){console.log('done then' val);}

    fail的回調列表failCallbacks的樣式是

      failCallbacks = [
        function () {// state = [ resolved | rejected ]state = stateString;// [ reject_list | resolve_list ].disable; progress_list.lock},function () {list = stack = memory = undefined;return this;},function () {stack = undefined;if ( !memory ) {self.disable();}return this;},function () {var returned = fn && fn.apply( this, arguments );if ( returned && jQuery.isFunction( returned.promise ) ) {returned.promise().done( newDefer.resolve ).fail( newDefer.reject ).progress( newDefer.notify );} else {newDefer[ action "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );}}
    ]

    前面三個元素是Callbacks自帶的,

    第四個是.then的第二個參數添加的,對應的fn是function(val){console.log('fail then' val);}

    progress對應回調列表progressCallbacks的樣子是

    progressCallbacks = [
        function () {var returned = fn && fn.apply( this, arguments );if ( returned && jQuery.isFunction( returned.promise ) ) {returned.promise().done( newDefer.resolve ).fail( newDefer.reject ).progress( newDefer.notify );} else {newDefer[ action "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );}}
    ]

    只有一個元素是.then的第三個參數添加的,fn對應為function(val){console.log('progress then' val);})

    總結

    以上是生活随笔為你收集整理的深入解析jQuery中的延时对象的概念的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。