使用 then 和 resolve 方法
var d1 = $.Deferred();// 注冊回調函數d1.then(function(data){console.log('First function: ' + data.state);}, function(err){console.log('Second function: ' + err);});// 做一些耗時的操作// 改變 deferred 對象狀態為 resolved// 回調函數將被調用,打印信息:First function: successedd1.resolve({state: 'successed'});
使用 then 和 reject 方法
var d2 = $.Deferred();// 注冊回調函數d2.then(function(data){console.log('First function: ' + data.state);}, function(err){console.log('Second function: ' + err.state);});// 改變 deferred 對象狀態為 rejected// 回調函數將被調用,打印信息:Second function: failedd2.reject({state: 'failed'});
使用 done 方法可以指定當 deferred 對象狀態變成 resolved 時調用的函數
var deferred = $.Deferred();deferred.done(function(data){console.log('Done: ' + data.state);});deferred.resolve({state: 'successed'});
使用 fail 方法可以指定當 deferred 對象狀態變成 rejected 時調用的函數
var deferred = $.Deferred();deferred.fail(function(err){console.log('Fail: ' + err.state);})deferred.resolve({state: 'failed'});
always 方法接受一個函數作為參數,只要 Deferred 對象的狀態發生變化,該函數都會被調用。
因為 then/done/fail 函數返回的仍然是類 Deferred 對象,所以我們可以使用他們來指定多個回調函數.
下面這個例子用 done/fail 來指定多個
var deferred = $.Deferred();deferred.done(data=>{// Do something}).done(data=>){// Do something}.fail(err=>{// Handle the error}).always(()=>{// Clean the environment})
JQuery 還提供了 Promise 對象,可以通過 Deferred 對象的 promise
方法來獲取該對象的 Promise 對象。=
Promise 對象有以下特點:
Promise 對象沒有 reject
/resolve
方法
Promise 對象的狀態跟 Deferred 對象保持一致
Promise 對象通過 state()
方法獲取跟它綁定的 Deferred 的狀態
Proimse 對象也可以使用 then
/done
/fail
方法來指定回調函數
Promise 可以調用 promise 方法獲取它自身
var deferred = $.Deferred();var promise = deferred.promise();deferred.reject();console.log(deferred.state()); // rejectedconsole.log(promise.state()); // rejectedconsole.log(promise.promise() === promise); // true, Promise 對象的 promis() 方法返回的是它自己
done/fail 返回的是 Deferred 對象自身
then 方法返回的是一個新的 Promise 對象
var d1 = $.Deferred();var d2 = d1.done();var d3 = d1.fail();console.log(d1 === d2); // trueconsole.log(d1 === d3); // true
使用 then 方法我們需要明白的幾個關鍵點是:
Deferred 對象的 then
方法, 會創建一個新的 Deferred 對象,并返回新 Deferred 對象的 Promise 對象。
而且 then
方法返回的對象 跟 Deferred 對象的 Promise 對象不相等, 多次調用 then 對象會產生多個 Deferred 對象。
下面的例子對比了多次調用 then 方法產生的 Promise 對象
var d1 = $.Deferred();var p2 = d1.then(); // 調用 then 方法返回一個 Promise 對象var p3 = d1.then(); // 調用 then 方法返回一個新的 Promise 對象console.log('reject' in d1); // false, 查看 then 方法返回的對象中是否有 reject 方法console.log('reject' in p2); // false, 查看 then 方法返回的對象中是否有 reject 方法console.log(p2 === d1); // false, 檢查 d1 是否與 p2 相等console.log(p2 === d1.promise()); // false, 查看 d1 的 promise 是否與 p2 相等console.log(p2 === p3); // false, p2 和 p3 的值不同
Deferred 對象狀態發生變化后, 等待一段時間后 then 方法產生的 Promise 對象的狀態才會發生相應的變化
var deferred = $.Deferred();var new_promise = deferred.then();deferred.reject('reject')console.log(`d1 state: ${deferred.state()}`); // rejectedconsole.log(`new_promise state: ${new_promise.state()}`); // pendingsetTimeout(`console.log("new_promise state after 100 miliseconds: ${new_promise.state()}")`, 100); // 100 毫秒后, new_promise 的狀態變成了 rejected
Deferred 對象的狀態發生改變后,then 方法產生的 Promise 對象的狀態并沒有立即發生變化, 而是等待了一段時間后才改變。
這段時間內,發生了什么那?
我們以調用 Deferred 對象的 resolve 方法作為例子來說明。 調用 reject 方法的情況與此類似。
首先假設我們構造了Deferred 對象 d1
然后調用 then 方法,并且傳入兩個函數作為參數 fun1, fun2: var p2 = d1.then(fun1, fun2)
調用 d1.resolve(data)
方法將 d1 的狀態設置為 resolved, 此時d1 的狀態是 resolved, p2 的狀態是 pending
fun1 會被調用, 參數為 d1.resolve
方法的參數: var new_data = fun1(data)
假設 p2 對應的 Deferred 對象是 d2.
d2 的 resolve 方法會被調用, 參數為 fun1 的返回值: d2.resolve(new_data)
p2 的狀態變為 resolved
p2 的回調函數會被調用
下面的代碼展示了 then 方法產生的 Promise 對象的狀態變化。以及如何給回調函數傳遞參數
var d1 = $.Deferred();function fun1(data){console.log(`p2 state in fun1: ${p2.state()}`);console.log(`data in fun1: ${data}`);return data * 3;}function fun2(error){return 'new data from fun2';}var p2 = d1.then(fun1, fun2);p2.done(data=>{console.log(`p2 state in done: ${p2.state()}`);console.log(`data in done: ${data}`);});d1.resolve(10);/* 屏幕
明白了 Deferred 的原理,我們就可以使用 Deferred.
下面一段代碼定義了一個函數, 在函數中定義了一些耗時的操作。
函數返回 Promise 對象, 可以使用 done/fail/then 注冊回調函數
function say_hello(){// 創建 Deferred 對象var deferred = $.Deferred();// 做一些耗時的操作,操作完成后調用 resolve 或者 reject 函數結束。// 我們用 setTimeout 函數模擬一段耗時操作:// 等待五秒鐘后,調用 Deferred 的 resolve 方法來改變狀態setTimeout(deferred.resolve.bind(deferred, 'hello world'), 5000);// 也可以使用 AJAX 操作/* $.getJSON('/api/names').done(data=>{ if(data.state == 'successed'){ deferred.resolve(data); }else{ deferred.reject(data); } }); */return deferred.promise(); // 返回 promise 對象, 防止外界對 Deferred 對象的狀態進行改變}// 調用 say_hello函數,并使用 done/fail/then 方法注冊回調函數say_hello().done(msg=>{console.log(msg);});
跟 ES2016 中 Prmomise.all
函數類似。
JQuery 提供了 when
函數, 它可以接受多個 Deferred/Promise 對象作為參數。并返回一個 Promise 對象。
新的 Promise 對象會等待參數中所有的對象狀態變為 resolved/reject。
如果參數中任何一個對象的狀態變為 rejected, 那么 Promise 對象的狀態變為 rejected。 否則變為 resolved。
// 創建一個函數,如果參數大于500, 則將內置的 Deferred 對象狀態變為 resolved// 如果參數小于500, 則將內置的 Deferred 對象狀態變為 rejectedfunction get_promise(delay){// 創建 Deferred 對象var deferred = $.Deferred();if(delay > 500){setTimeout(deferred.resolve.bind(deferred, delay/100), delay);}else{setTimeout(deferred.reject.bind(deferred, delay/100), delay);}return deferred.promise(); // 返回 promise 對象}// 如果任一參數狀態轉變為 rejected, when 函數產生的 promise 對象狀態會理解變為 rejected。// 并將第一個 Deferred 對象的錯誤信息傳遞給回調函數$.when(get_promise(800), get_promise(100), get_promise(300)).fail(error=>{console.log(error); // 1});// 否則 when 函數會等待所有的 Deferred 對象狀態變為 resolved, 并將所有 Deferred 對象的返回值依次傳遞給回調函數$.when(get_promise(900), get_promise(600), get_promise(1000)).done((d1, d2, d3)=>{console.log(d1); // 9console.log(d2); // 6console.log(d3); // 10});$.when(get_promise(800), get_promise(900), get_promise(1000)).done((...datas)=>{console.log(datas); // [8, 9, 10]});
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com