https://blog.csdn.net/educast/article/details/71422502
https://blog.csdn.net/web_xyk/article/details/52292183
版權聲明:本文為博主原創文章,未經博主允許不得轉載。轉載請標明出處:http://blog.csdn.net/ligang2585116! https://blog.csdn.net/ligang2585116/article/details/51589073
在講述Promise時,曾提及過Deferred對象。下面內容,詳細闡述Deferred對象及其用法。
一、為什么使用Deferred對象
目前,大部分瀏覽器已經支持原生Promise寫法,但對於IE這種“古板”的瀏覽器我們只能硬着頭皮去兼容它。Github中提供了好多插件去支持。例如babel-polyfill。但是其對目前主流前端構建工具兼容性不是很好(比如Grunt)。所以,難道我們只能去放棄Promise???當然不是,Deferred對象就是一個很好的替代方案。
二、什么是Deferred對象
defer,推遲;延期。含義就是”延遲”到未來某個點再執行。
在開發中,我們經常遇到某些耗時很長的javascript操作。其中,既有異步的操作(比如ajax讀取服務器數據),也有同步的操作(比如遍歷一個大型數組),它們都不是立即能得到結果的。通常的做法是,為它們指定回調函數(callback)。即事先規定,一旦它們運行結束,應該調用哪些函數。但是,一旦回調層級過深,處理和維護會變得相當困難。jQuery開發團隊就設計了deferred對象,來作為回調函數的解決方案。
三、ajax操作的鏈式寫法
$.ajax({
url: "http://localhost:8888",
success: function(){
console.log("哈哈,成功了!");
},
error: function(){
console.log("出錯啦!");
}
});
1
2
3
4
5
6
7
8
9
$.ajax()操作完成后,如果使用的是低於1.5.0版本的jQuery,返回的是XHR對象,你沒法進行鏈式操作;如果高於1.5.0版本,返回的是deferred對象,可以進行鏈式操作。
$.ajax("http://localhost:8888")
.done(function(){
console.log("哈哈,成功了!");
})
.fail(function(){
console.log("出錯啦!");
});
1
2
3
4
5
6
7
四、同一操作指定多個回調函數
deferred對象允許自由添加多個回調函數。
$.ajax("http://localhost:8888")
.done(function(){
console.log("哈哈,成功了!");
})
.fail(function(){
console.log("出錯啦!");
})
.done(function(){
console.log("第二個成功回調函數!");
});
1
2
3
4
5
6
7
8
9
10
注意:回調函數可以添加任意多個,其按照添加順序執行。
五、多個操作指定同一回調函數
deferred對象允許為多個事件指定一個回調函數
$.when($.ajax("http://localhost:8888"),$.ajax("http://localhost:9999"))
.done(function(){
console.log("哈哈,成功了!");
})
.fail(function(){
console.log("出錯啦!");
});
1
2
3
4
5
6
7
上述示例:如果都成功了,就運行done()指定的回調函數;
如果有一個失敗或都失敗了,就執行fail()指定的回調函數。
六、本地操作使用回到函數
deferred對象,把這一套回調函數接口,從ajax操作擴展到了所有操作。
var wait = function(){
var tasks = function(){
console.log("wait函數執行完畢!");
};
setTimeout(tasks, 5000);
};
1
2
3
4
5
6
我們想,在wait執行完,輸出”哈哈,成功了!”
由於jQuery.when(deferreds)方法只能接收defferred對象作為參數,所以我們需對上述wait改寫!
var dtd = $.Deferred(); // 新建一個Deferred對象
var wait = function(dtd){
var tasks = function(){
console.log("wait函數執行完畢!");
dtd.resolve(); // 改變Deferred對象的執行狀態
};
setTimeout(tasks, 5000);
return dtd; // 返回deferred對象
};
$.when(wait(dtd))
.done(function(){
console.log("哈哈,成功了!");
})
.fail(function(){
console.log("出錯了!");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
上述示例中,提及到了deferred.resolve()。說明其作用需要先說一下jQuery規定deferred對象的三種執行狀態:未完成、已完成和已失敗。
如果執行狀態是”已完成”(resolved),deferred對象立刻調用done()方法指定的回調函數;
如果執行狀態是”已失敗”,調用fail()方法指定的回調函數;
如果執行狀態是”未完成”,則繼續等待,或者調用progress()方法指定的回調函數(jQuery1.7版本添加)。
七、deferred.promise()方法
上面示例實現了我們的要求:在wait執行完,輸出”哈哈,成功了!”
但是作為JavaScript忍者,我們是不允許這樣抒寫的,因為dtd是一個全局變量,它的執行狀態可以從外部改變。
var dtd = $.Deferred(); // 新建一個Deferred對象
var wait = function(dtd){
var tasks = function(){
console.log("wait函數執行完畢!");
dtd.resolve(); // 改變Deferred對象的執行狀態
};
setTimeout(tasks, 5000);
return dtd; // 返回deferred對象
};
$.when(wait(dtd))
.done(function(){
console.log("哈哈,成功了!");
})
.fail(function(){
console.log("出錯了!");
});
dtd.resolve();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在代碼的尾部加了一行dtd.resolve(),這就改變了dtd對象的執行狀態,因此導致done()方法立刻執行,跳出”哈哈,成功了!”的提示框,等5秒之后再跳出”wait函數執行完畢!”的提示框。
解決上述“全局變量”問題:我們使用deferred.promise()
其作用:在原來的deferred對象上返回Promise對象,后者只開放與改變執行狀態無關的方法(比如done()方法和fail()方法),屏蔽與改變執行狀態有關的方法(比如resolve()方法和reject()方法),從而使得執行狀態不能被改變。
圖:deffered.png
圖:deferred.promise().png
方式一:deferred.promise
var wait = function(){
var dtd = $.Deferred();
var tasks = function(){
console.log("wait函數執行完畢!");
dtd.resolve(); // 改變Deferred對象的執行狀態
};
setTimeout(tasks, 5000);
return dtd.promise(); // 返回Promise對象
};
$.when(wait())
.done(function(){
console.log("哈哈,成功了!");
})
.fail(function(){
console.log("出錯了!");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
方式二:在wait對象上部署deferred接口
var dtd = $.Deferred(); // 生成Deferred對象
var wait = function(dtd){
var tasks = function(){
console.log("執行完畢!");
dtd.resolve(); // 改變Deferred對象的執行狀態
};
setTimeout(tasks,5000);
};
// 在wait對象上部署Deferred接口
dtd.promise(wait);
wait.done(function(){
console.log("哈哈,成功了!");
}).fail(function(){
console.log("出錯啦!");
});
wait(dtd); // 調用wait函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
八、deferred對象的方法
$.Deferred() 生成一個deferred對象。
deferred.done(function(){}) 指定操作成功時的回調函數
deferred.fail(function(){}) 指定操作失敗時的回調函數
deferred.promise()
沒有參數時,返回一個新的deferred對象,該對象的運行狀態無法被改變;
接受參數時,作用為在參數對象上部署deferred接口。
deferred.resolve() 手動改變deferred對象的運行狀態為”已完成”,從而立即觸發done()方法。
deferred.reject() 手動改變deferred對象的運行狀態變為”已失敗”,從而立即觸發fail()方法。
$.when() 為多個操作指定回調函數。
deferred.then() 有時為了省事,可以把done()和fail()合在一起寫,這就是then()方法。
$.when($.ajax("/main.php" ))
.then(successFunc, failureFunc );
1
2
如果then()有兩個參數,那么第一個參數是done()方法的回調函數,第二個參數是fail()方法的回調方法。如果then()只有一個參數,那么等同於done()。
9. deferred.always()這個方法也是用來指定回調函數的,它的作用是,不管調用的是deferred.resolve()還是deferred.reject(),最后總是執行。
$.ajax("test.html")
.always(function(){
console.log("已執行!");
});
---------------------
作者:奮飛
來源:CSDN
原文:https://blog.csdn.net/ligang2585116/article/details/51589073?utm_source=copy
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!