promise ajax 队列,ES6中的promise,从使用promise封装ajax说起
1為啥要用promise?
js是單線程的,理論上所有代碼都是同步的,從上到下一行行執行。然而就這樣傻傻解析運行js的話,碰到較重的任務時,會阻塞進程,如發送一個用戶是否登錄驗證請求,請求完成響應之前,下面的動作都不會執行,偽代碼如下:
//獲取XMLHttpRequest對象并發送請求
var xhr = new XMLHttpRequest()
xhr.open(method, url, async);
xhr.send(data);
//漫長的響應等待......
//根據用戶信息發送請求獲取對應數據
//使用數據渲染table列表
//獲取按鈕,綁定單擊事件
//......
用戶是否登錄驗證請求完成響應之前,后續所有任務都不會執行,用戶使用體驗極差。
于是聰明的程序員將任務分為兩類:
同步任務
異步任務(如網絡請求,加載圖片等)
同步任務由上到下,逐行執行,異步的進入Event Table并注冊函數,過后Event Table會將這個函數移入Event Queue,等主線程中的同步任務都執行完后主線程進入Event Queue執行異步代碼。該過程示意圖如下:
同步代碼與異步代碼的執行過程
修改上面的代碼得到:
//獲取XMLHttpRequest對象并發送請求
var xhr = new XMLHttpRequest()
xhr.open(method, url, async);
xhr.onloadend = function () {
//漫長的響應等待......
}
xhr.send(data);
//根據用戶信息發送請求獲取對應數據
//使用數據渲染table列表
//獲取按鈕,綁定單擊事件
//......
如此,漫長的網絡請求過程就不會阻塞之后的//根據用戶信息發送請求獲取對應數據 //使用數據渲染table列表 //獲取按鈕,綁定單擊事件 //......等任務了,等它們都執行完才會去執行等待網絡請求響應的任務。
但上面的邏輯有個bug,就是這兩個任務//根據用戶信息發送請求獲取對應數據//使用數據渲染table列表應該在用戶是否登錄的驗證請求完成之后進行,而為了使該請求不阻塞后續任務已經將其修改為異步執行了,那么應該放在其后并依賴它的返回結果的任務應該放置它的回調函數里去,偽代碼如下:
//獲取XMLHttpRequest對象并發送請求
var xhr = new XMLHttpRequest()
xhr.open(method, url);
xhr.onloadend = function () {
//漫長的響應等待......
//根據用戶信息發送請求獲取對應數據
xxx.onloadend = function(){
//使用數據渲染table列表
function renderData(){
}
}
}
xhr.send(data);
//獲取按鈕,綁定單擊事件
//......
如此簡單的邏輯已經使用了兩層異步函數嵌套,再加上內層的渲染函數,三層了!!!,業務邏輯再復雜點,嵌套層數會瘋狂增加,如此代碼已經失去了可閱讀性。
于是聰明的程序員發明了promise
2 promise如何使用 使函數嵌套變得清晰
所謂Promise,簡單說就是一個容器,一個對象,可以獲取異步操作的消息,并可在后續語法操作then中使用異步操作的返回結果,
偽代碼如下:
new Promise(function(resolve,reject){
//異步操作
//。。。
if(成功){
resolve(data)
}else{
reject(data)
}
}).then(function(data){
//這里可以拿到data
})
我們使用promise將ajax請求簡單封裝一下,看看其如何使用:
常規的ajax請求分四步:
//獲取XMLHttpRequest對象并發送請求
var xhr = new XMLHttpRequest();
//準備連接與參數
xhr.open(method, url);
//監聽響應事件(當然還有其他事件)
xhr.onloadend = function () {
}
//發送請求
xhr.send(data);
使用promise對其進行封裝的偽代碼如下:
function ajaxPromise(url, method, data) {
var xhr = new XMLHttpRequest()
return new Promise(function (resolve, reject) {
xhr.open(method, url, async);
xhr.timeout = options.timeout;
xhr.onloadend = function () {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)
resolve(xhr);//成功時使用resolve將數據返給后續操作
else
reject(xhr)//失敗時使用resolve將數據返給后續操作
}
xhr.send(data);
})
}
那么本文開頭的業務邏輯可改寫成下面的偽代碼:
//發送用戶是否登錄請求
ajaxPromise(url, method, data)
.then(function(data){
//根據用戶信息發送請求獲取對應數據
return ajaxPromise(url, method, data)
})
.then(function(data2){
//使用數據渲染table列表
})
//獲取按鈕,綁定單擊事件
//......
原來極其難以閱讀的函數嵌套,變成了清晰的幾個.then
下面是詳細的對ajax的封裝:
function requestNumber(url, method, data, async, timeout) {
var xhr = new XMLHttpRequest()
return new Promise(function (resolve, reject) {
xhr.open(method, url, async);
xhr.timeout = options.timeout;
xhr.onloadend = function () {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)
resolve(xhr);
else
reject({
errorType: 'status_error',
xhr: xhr
})
}
xhr.send(data);
//錯誤處理
xhr.onabort = function () {
reject(new Error({
errorType: 'abort_error',
xhr: xhr
}));
}
xhr.ontimeout = function () {
reject({
errorType: 'timeout_error',
xhr: xhr
});
}
xhr.onerror = function () {
reject({
errorType: 'onerror',
xhr: xhr
})
}
})
}
3多個網絡請求的幾種關系的處理
鏈式關系
使用promise的then將其串聯
request1().then(return request2).then(return request3)......
并列關系
并列都成功才執行后續動作
Promise.all([request1,request2,request3...]).then(function([data1,data2,data3]){
//后續動作
})
并列并只要有一個成功就執行后續動作
Promise.race([request1,request2,request3...]).then(function([data1,data2,data3]){
//后續動作
})
4 使用promise封裝ajax的弊端
這得從javaScript的執行機制說起。
事件循環--同步任務先執行,異步任務放隊列。
同步任務執行完再執行異步任務,異步任務里也可能有同步任務和異步任務。
先執行同步再執行異步、、、、、、
如此循環,最終執行完整個腳本邏輯。
任務還分宏任務和微任務。
宏任務是宿主環境提供的,如來自window的setTimeout ,ajax等。
微任務是語言本身提供的,如promise等。
一個javascript腳本的大致執行順序如下:
整個javascript腳本上同步代碼的執行作為一個宏任務最先被執行。
其后的setTimeout setInterval ajax等被放入任務隊列后續執行。
而promise作為一個微任務,其執行順序是上一個宏任務執行之后,下一個宏任務執行之前。
無論宏任務還是微任務,其中也可能包含同步代碼和異步代碼,于是依據上述3步再開啟一個循環。
根據上述原因,封裝到promise的ajax代碼,其發送請求的那三步(new open send)會被延后到整個腳本同步代碼執行完,而且將響應回調函數延后到現有任務隊列的最后,如果大量使用那么會大大降低請求效率。這就是使用promise封裝ajax的弊端,所以那些沒有串并聯關系的請求盡量使用原生的ajax做請求。
ES6總篇--目錄
總結
以上是生活随笔為你收集整理的promise ajax 队列,ES6中的promise,从使用promise封装ajax说起的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 华为锁屏后微信无法连接服务器,怎么解决华
- 下一篇: 服务器充电桩是什么显示,请教一个问题,高
