首頁  >  文章  >  web前端  >  jQuery中的deferred物件和extend區別詳解

jQuery中的deferred物件和extend區別詳解

小云云
小云云原創
2018-01-12 10:46:531149瀏覽

本文主要介紹了jQuery中的deferred物件和extend方法,具有很好的參考價值。下面跟著小編一起來看吧,希望能幫助大家。

1 deferred物件

deferred物件是jQuery的回呼函數解決方案,它是從jQuery1.5.0版本開始引入的功能

deferred物件的方法

(1) $.Deferred() 產生一個deferred物件。

(2) deferred.done() 指定操作成功時的回呼函數

#(3) deferred.fail() 指定操作失敗時的回呼函數

#(4 ) deferred.promise() 沒有參數時,返回一個新的deferred對象,該對象的運行狀態無法被改變;接受參數時,作用為在參數對像上部署deferred接口。

(5) deferred.resolve() 手動改變deferred物件的運作狀態為"已完成",從而立即觸發done()方法。

(6)deferred.reject() 這個方法與deferred.resolve()正好相反,呼叫後將deferred物件的運行狀態變成"已失敗",從而立即觸發fail()方法

(7) $.when() 為多個運算指定回呼函數。

除了這些方法以外,deferred物件還有二個重要方法,上面的教學中沒有涉及。

(8)deferred.then()

有時為了省事,可以把done()和fail()合在一起寫,這就是then()方法。

  $.when($.ajax( "/main.php" ))
  .then(successFunc, failureFunc );

如果then()有兩個參數,那麼第一個參數是done()方法的回呼函數,第二個參數是fail()方法的回呼方法。如果then()只有一個參數,那麼等同於done()。

(9)deferred.always()

這個方法也是用來指定回呼函數的,它的作用是,不管呼叫的是deferred.resolve()還是deferred.reject() ,最後總是執行。

$.ajax( "test.html" )
.always( function() { alert("已执行!");} );

來點兒

1)ajax操作的鍊式寫法

先回顧jQuery的ajax操作的傳統寫法:

$.ajax({

    url: "test.html",

    success: function(){
      alert("哈哈,成功了!");
    },

    error:function(){
      alert("出错啦!");
    }
  });

在上面的程式碼中,$.ajax()接受一個物件參數,這個物件包含兩個方法:success方法指定操作成功後的回呼函數,error方法指定操作失敗後的回呼函數。

$.ajax()操作完成後,如果使用的是低於1.5.0版本的jQuery,返回的是XHR對象,你沒法進行鍊式操作;如果高於1.5.0版本,傳回的是deferred對象,可以進行鍊式操作。

有了deferred物件之後,可以這樣寫了

$.ajax("test.html")

  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });

上面程式碼中的done()相當於success方法,fail()相當於error方法。採用鍊式寫法以後,程式碼的可讀性大大提高。

2)指定同一操作的多個回呼函數

deferred物件的一大好處,就是它允許你自由添加多個回調函數。

還是以上面的程式碼為例,如果ajax操作成功後,除了原來的回呼函數,我還想再運行一個回呼函數,怎麼辦?

很簡單,直接把它加在後面就行了。

$.ajax("test.html")

  .done(function(){ alert("哈哈,成功了!");} )

  .fail(function(){ alert("出错啦!"); } )
  .done(function(){ alert("第二个回调函数!");} );

回呼函數可以新增任意多個,它們按照新增順序執行。

3)為多個運算指定回呼函數

deferred物件的另一個好處,就是它允許你為多個事件指定一個回呼函數,這是傳統寫法做不到的。

請看下面的程式碼,它用到了一個新的方法$.when():#​​##

$.when($.ajax("test1.html"), $.ajax("test2.html"))

  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });
這段程式碼的意思是,先執行兩個動作$.ajax("test1 .html")和$.ajax("test2.html"),如果都成功了,就運行done()指定的回調函數;如果有一個失敗或都失敗了,就執行fail()指定的回調函數。

4)普通操作的回呼函數接口(上)

deferred物件的最大優點,就是它把這套回調函數接口,從ajax操作擴展到了所有操作。也就是說,任何一個操作----不管是ajax操作還是本地操作,也不管是非同步操作還是同步操作----都可以使用deferred物件的各種方法,指定回調函數。

我們來看一個具體的例子。假設有一個很耗時的操作wait:

var wait = function(){

    var tasks = function(){

      alert("执行完毕!");

    };

    setTimeout(tasks,5000);
  };
我們為它指定回呼函數,該怎麼做呢?

很自然的,你會想到,可以用$.when():#​​##
$.when(wait())

  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });

但是,這樣寫的話,done()方法會立即執行,起不到回呼函數的作用。原因在於$.when()的參數只能是deferred對象,所以必須對wait()進行改寫:

var dtd = $.Deferred(); // 新建一个deferred对象

  var wait = function(dtd){

    var tasks = function(){

      alert("执行完毕!");

      dtd.resolve(); // 改变deferred对象的执行状态

    };

    setTimeout(tasks,5000);

    return dtd;
  };

現在,wait()函數傳回的是deferred對象,這就可以加上鍊式操作了。

$.when(wait(dtd))

  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });

wait()函數運行完,就會自動執行done()方法指定的回呼函數。

5)deferred.resolve()方法和deferred.reject()方法 

jQuery規定,deferred物件有三種執行狀態----未完成,已完成和已失敗。如果執行狀態是"已完成"(resolved),deferred物件立刻呼叫done()方法指定的回呼函數;如果執行狀態是"已失敗",則呼叫fail()方法指定的回呼函數;如果執行狀態是"未完成",則繼

續等待,或呼叫progress()方法指定的回呼函數(jQuery1.7版本新增)。

前面部分的ajax操作时,deferred对象会根据返回结果,自动改变自身的执行状态;但是,在wait()函数中,这个执行状态必须由程序员手动指定。dtd.resolve()的意思是,将dtd对象的执行状态从"未完成"改为"已完成",从而触发done()方法。

类似的,还存在一个deferred.reject()方法,作用是将dtd对象的执行状态从"未完成"改为"已失败",从而触发fail()方法。

var dtd = $.Deferred(); // 新建一个Deferred对象

  var wait = function(dtd){

    var tasks = function(){

      alert("执行完毕!");

      dtd.reject(); // 改变Deferred对象的执行状态

    };

    setTimeout(tasks,5000);

    return dtd;

  };

  $.when(wait(dtd))

  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });

6)deferred.promise()方法

上面这种写法,还是有问题。那就是dtd是一个全局对象,所以它的执行状态可以从外部改变。

请看下面的代码:

var dtd = $.Deferred(); // 新建一个Deferred对象

  var wait = function(dtd){

    var tasks = function(){

      alert("执行完毕!");

      dtd.resolve(); // 改变Deferred对象的执行状态

    };

    setTimeout(tasks,5000);

    return dtd;

  };

  $.when(wait(dtd))

  .done(function(){ alert("哈哈,成功了!"); })

  .fail(function(){ alert("出错啦!"); });
  dtd.resolve();

我在代码的尾部加了一行dtd.resolve(),这就改变了dtd对象的执行状态,因此导致done()方法立刻执行,跳出"哈哈,成功了!"的提示框,等5秒之后再跳出"执行完毕!"的提示框。

为了避免这种情况,jQuery提供了deferred.promise()方法。它的作用是,在原来的deferred对象上返回另一个deferred对象,后者只开放与改变执行状态无关的方法(比如done()方法和fail()方法),屏蔽与改变执行状态有关的方法(比如resolve()方法和

reject()方法),从而使得执行状态不能被改变。

请看下面的代码:

var dtd = $.Deferred(); // 新建一个Deferred对象

  var wait = function(dtd){

    var tasks = function(){

      alert("执行完毕!");

      dtd.resolve(); // 改变Deferred对象的执行状态

    };

    setTimeout(tasks,5000);

    return dtd.promise(); // 返回promise对象

  };

  var d = wait(dtd); // 新建一个d对象,改为对这个对象进行操作

  $.when(d)

  .done(function(){ alert("哈哈,成功了!"); })

  .fail(function(){ alert("出错啦!"); });
  d.resolve(); // 此时,这个语句是无效的

在上面的这段代码中,wait()函数返回的是promise对象。然后,我们把回调函数绑定在这个对象上面,而不是原来的deferred对象上面。这样的好处是,无法改变这个对象的执行状态,要想改变执行状态,只能操作原来的deferred对象。

不过,更好的写法是将dtd对象变成wait()函数的内部对象。

var wait = function(dtd){

    var dtd = $.Deferred(); //在函数内部,新建一个Deferred对象

    var tasks = function(){

      alert("执行完毕!");

      dtd.resolve(); // 改变Deferred对象的执行状态

    };

    setTimeout(tasks,5000);

    return dtd.promise(); // 返回promise对象

  };

  $.when(wait())

  .done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });

7)普通操作的回调函数接口(中)

另一种防止执行状态被外部改变的方法,是使用deferred对象的建构函数$.Deferred()。

这时,wait函数还是保持不变,我们直接把它传入$.Deferred():

$.Deferred(wait)
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });

jQuery规定,$.Deferred()可以接受一个函数名(注意,是函数名)作为参数,$.Deferred()所生成的deferred对象将作为这个函数的默认参数。

8)普通操作的回调函数接口(下)

除了上面两种方法以外,我们还可以直接在wait对象上部署deferred接口。

var dtd = $.Deferred(); // 生成Deferred对象

  var wait = function(dtd){

    var tasks = function(){

      alert("执行完毕!");

      dtd.resolve(); // 改变Deferred对象的执行状态

    };

    setTimeout(tasks,5000);

  };

  dtd.promise(wait);

  wait.done(function(){ alert("哈哈,成功了!"); })

  .fail(function(){ alert("出错啦!"); });
  wait(dtd);

这里的关键是dtd.promise(wait)这一行,它的作用就是在wait对象上部署Deferred接口。正是因为有了这一行,后面才能直接在wait上面调用done()和fail()。

2 extend方法

JQuery的extend扩展方法:

Jquery的扩展方法extend是我们在写插件的过程中常用的方法,该方法有一些重载原型,在此,我们一起去了解了解。

1)Jquery的扩展方法原型是:   

extend(dest,src1,src2,src3...);

它的含义是将src1,src2,src3...合并到dest中,返回值为合并后的dest,由此可以看出该方法合并后,是修改了dest的结构的。如果想要得到合并的结果却又不想修改dest的结构,可以如下使用:

var newSrc=$.extend({},src1,src2,src3...)//也就是将"{}"作为dest参数。

这样就可以将src1,src2,src3...进行合并,然后将合并结果返回给newSrc了。如下例:

var result=$.extend({},{name:"Tom",age:21},{name:"Jerry",sex:"Boy"})

那么合并后的结果

result={name:"Jerry",age:21,sex:"Boy"}

也就是说后面的参数如果和前面的参数存在相同的名称,那么后面的会覆盖前面的参数值。

2)省略dest参数

上述的extend方法原型中的dest参数是可以省略的,如果省略了,则该方法就只能有一个src参数,而且是将该src合并到调用extend方法的对象中去,如:

$.extend(src)

该方法就是将src合并到jquery的全局对象中去,如:

$.extend({
hello:function(){alert('hello');}
});

就是将hello方法合并到jquery的全局对象中。

$.fn.extend(src)

该方法将src合并到jquery的实例对象中去,如:

$.fn.extend({
hello:function(){alert('hello');}
});

就是将hello方法合并到jquery的实例对象中。

下面例举几个常用的扩展实例:

$.extend({net:{}});

这是在jquery全局对象中扩展一个net命名空间。

$.extend($.net,{
hello:function(){alert('hello');}
})

这是将hello方法扩展到之前扩展的Jquery的net命名空间中去。

3)Jquery的extend方法还有一个重载原型: 

extend(boolean,dest,src1,src2,src3...)

第一个参数boolean代表是否进行深度拷贝,其余参数和前面介绍的一致,什么叫深层拷贝,我们看一个例子:

var result=$.extend( true, {}, 
{ name: "John", location: {city: "Boston",county:"USA"} }, 
{ last: "Resig", location: {state: "MA",county:"China"} } );

我们可以看出src1中嵌套子对象location:{city:"Boston"},src2中也嵌套子对象location:{state:"MA"},第一个深度拷贝参数为true,那么合并后的结果就是:

result={name:"John",last:"Resig",
location:{city:"Boston",state:"MA",county:"China"}}

也就是说它会将src中的嵌套子对象也进行合并,而如果第一个参数boolean为false,我们看看合并的结果是什么,如下:

var result=$.extend( false, {}, 
{ name: "John", location:{city: "Boston",county:"USA"} }, 
{ last: "Resig", location: {state: "MA",county:"China"} } 
);

那么合并后的结果就是:

result={name:"John",last:"Resig",location:{state:"MA",county:"China"}}

以上是网上看到的两篇分别对jQuery中的deferred对象和extend方法的介绍,感觉比较详细而且容易理解,所以把它们整理到一起与大家分享!

相关推荐:

jQuery源码解析Deferred异步对象的方法

$.Deferred(),for循环内异步请求问题的解决方法

JQuery Deferred 对象剖析

以上是jQuery中的deferred物件和extend區別詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn