jQuery(五): Deferred 有啥用 通常來說,js請求數據,無論是非同步還是同步,都不會立即獲取到結果,通常而言,我們一般是是使用回調函數再執行,而 deferred就是解決jQuery的回調函數方案,總的來說,deferred對象就是為了將某個回調函數延遲到某個時機再執行. 1. aja ...
jQuery(五): Deferred
有啥用
通常來說,js請求數據,無論是非同步還是同步,都不會立即獲取到結果,通常而言,我們一般是是使用回調函數再執行,而 deferred就是解決jQuery的回調函數方案,總的來說,deferred對象就是為了將某個回調函數延遲到某個時機再執行.
ajax鏈式寫法:
//一般寫法: $.ajax({ url: '', success: function(){}, error: function(){}, }) //deferred $.ajax(url) .done(function(){}) //相當於success .fail(function(){})
指定同一操作的多個函數,允許添加多個函數
寫法也很簡單,直接添加在後面就可以了。$.ajax(url) .done(function(){}) .fail(function(){}) .done(function(){})
為多個函數添加指定回調,可以為多個不同的函數添加同一個回調事件
為兩個函數執行操作,如果都成功了就執行done中的回調,如果有一個失敗或全部都失敗,就執行fail中的回調$.when($.ajax(url),$.ajax(url2)) .done() .fail()
普通操作的回調
deferred允許任何操作都可以使用deferred對象的方法,指定回調函數var wait = function(de){ var test = function(){ console.log('開始'); de.resolve(); } setTimeout(test, 3000); return de; } $.when(wait($.Deferred())) .done(function(){ console.log('已完成') }) .fail(function(){ console.log('失敗') })
註意: $.when()的參數只能是deferred對象。
咋處理
關於resolve && rejected
在上面的時候,會註意到一個resolve,並且會覺得這種鏈式寫法很眼熟,且對promise有一個簡單瞭解的話,大概就知道了。
$.deferred 同樣也是有三個不同的狀態:未完成,已完成,已失敗,當狀態處於已完成(resolve)下回自動調用done()中的回調函數,而resolve()就是人為將狀態值修改為已完成,同理可證rejected();promise: 同樣也是用於處理非同步函數,將非同步操作隊列化處理 簡單的promise new promise (function(resolve,rejected){ resolve('成功') }) .then(function(){}) promise.then 接受兩個參數: 一、 resolve 代表成功時調用的函數 二、 rejected 代表失敗時調用的回調 promise的三個狀態值: pending(初始狀態值), fulfilled(操作成功),rejected(操作失敗)
總的來說,核心就是:根據不同的狀態值調用回調。API
* $.Deferred()
* $.when()
* deferred.progress()
* deferred.promise()
* deferred.done()
* deferred.fail()
學習下
來看下jQ的源碼是怎麼處理的:
Deferred: function(func) {
var tuples = [
// action, add listener, callbacks,
// ... .then handlers, argument index, [final state]
["notify", "progress", jQuery.Callbacks("memory"),
jQuery.Callbacks("memory"), 2
],
["resolve", "done", jQuery.Callbacks("once memory"),
jQuery.Callbacks("once memory"), 0, "resolved"
],
["reject", "fail", jQuery.Callbacks("once memory"),
jQuery.Callbacks("once memory"), 1, "rejected"
]
],
state = 'pending',
// 延遲對象
deferred = {},
promise = {
state: function() {
return state
},
then: function(){},
promise: function(obj) {
return obj != null ? jQuery.extend(obj, promise): promise;
}
}
...
}
從代碼來看,定一個了數組tuples,以及初始狀態值。tuples存儲了三個狀態下的所需參數,來看下存儲了寫什麼內容:
[狀態, 對應的處理函數, 利用callbacks創建的回調隊列, then方法的回調隊列, index, 最終的狀態值],
我們可以看到最終的狀態值只有reject 和resolve才有。
ok,已經知道deferred的本質是根據不同的狀態調用不同的方法,並且使用callbacks添加函數,那麼把tuples遍歷一下,生成隊列;
源碼:
tuples.forEach(function(tuple){
var list = tuple[2], // 獲取到jQuery.callbacks返回,創建一個隊列
stateString = tuple[5], //獲取到最終狀態描述
//promise[ progress | done | fail ] = list.add
promise[tuple[1]] = list.add;
// 如果最終狀態值存在,即處於 reject|| resolve 狀態下;
if (stateString) {
list.add(
function() {
state = stateString;
}
....
)
}
// 延遲對象狀態 deferred.resolve()
//deferred[ 'resolve' | reject | notify] = function(){}
deferred[tuple[0]] = function() {
deferred[tuple[0]+"Width"](this === deferred ? promise : this, arguments);
return this;
}
//jQuery.callbacks.fireWith
//執行隊列,調用處理函數,綁定執行時的上下文
deferred[tuple[0] + "With"] = list.fireWith;
})
promise.promise(deferred);
return deferred;
已經遍歷生成了3個隊列,並將三個狀態方法掛載在了延遲對象上。
從代碼中可以看出,在調用deferred[ reject | resolve]時,其實是調用了deferred[ rejectWith | resolveWith]方法,本質上是對callbacks.fireWith的調用,以用來執行添加的回調函數,同時設置函數的上下文。
並且可以看的到,deferred[proress | done | fail] 其實是copy了callbacks.add方法,將回調函數添加在了執行隊列中。
另外關於對jQuery.deferred對象的詳解,使用,https://www.cnblogs.com/chris-oil/p/8922770.html 這篇博文轉載了阮大神的,可以瞅瞅