目錄
瞭解Promise
Promise :ES6提供的一個構造函數,處理異步事件。接收了一個參數爲函數,傳入resolve,reject兩個參數。resolve爲異步操作成功後執行的回調函數,reject爲異步操作失敗後執行的回調函數。Promise對象上有then,catch方法。例子:
function snycA(){
const promise = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('執行完成');
resolve('異步數據1');
},2000)
})
return promise
}
snycA().then((response)=>{
console.log(response);
})
輸出的結果爲:
Emmmmm...然而這種操作不就跟平時我們使用回調函數(將回調函數作爲參數傳入函數裏,函數裏面嵌套函數,等函數執行完成再去執行嵌套函數,就叫回調函數啦)一樣了嗎?下面的例子就是用回調函數實現上面所實現的效果:
//將callback作爲一個參數傳入函數中,待函數執行完成再執行回調函數
function syncA(callback){
setTimeout(()=>{
console.log("執行完成");
callback('回調數據1');
},2000)
}
syncA((data)=>{
console.log(data)
})
輸出的結果爲:
雖然回調函數也能實現同樣的效果,但是,如果callback也是一個異步操作,而且執行完後也需要有相應的回調函數,該怎麼辦呢?總不能再定義一個callback2,然後給callback傳進去吧。而Promise的優勢在於,可以在then方法中繼續寫Promise對象並返回,然後繼續調用then來進行回調操作。
Promiseの鏈式操作及Resolve的用法
promise能層層簡化多層回調的寫法,而Promise的精髓在於維護狀態,傳遞狀態。下面來簡單實現一下
function syncA(){
const P = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('執行syncA');
resolve('syncA-over')
})
})
return P;
}
function syncB(){
const P = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('執行syncB');
resolve('syncB-over')
})
})
return P;
}
function syncC(){
const P = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('執行syncC');
resolve('syncC-over')
})
})
return P;
}
syncA().then((data)=>{
console.log(data);
return syncB();
}).then((data)=>{
console.log(data);
return syncC();
}).then((data)=>{
console.log(data)
})
輸出結果爲:
這樣,每隔兩秒輸入按順序輸出syncA,syncB,syncC中的內容並執行,傳入resolve()的數據在then中也能直接拿到。
Reject的用法
reject的作用就是把Promise的狀態置爲rejected,這樣我們在then中就能捕捉到,然後執行“失敗”情況的回調。看下面的代碼。
//隨機生成一個1-10的數字,當數字小於8時調用reject,在then在輸出
function syncA(){
const P = new Promise((reslove,reject)=>{
setTimeout(()=>{
let num = Math.floor((Math.random * 10)+1)
if(num>8){
reslove(num)
}else{
reject('小於8')
}
})
})
return P;
}
syncA().then((num)=>{
console.log(num)
},(data)=>{
console.log(data)
})
輸出結果爲:
Catch的用法
catch方法與then中的第二個參數一樣,用來指定reject的回調,也就是上面的代碼可以寫成:
syncA().then((num)=>{
console.log(num)
})
.catch((data)=>{
console.log(data)
})
catch還有一個重要的作用!!!!當then方法中resolve拋出異常(代碼錯誤)時,也會進入到我們的catch中,將錯誤信息傳入到我們的catch中,代碼繼續往下執行,並不會中斷!與我們的try/catch語句有相同的功能。
all的用法
用Promise.all來執行,all接收一個數組參數,裏面的值最終都算返回Promise對象。這樣,三個異步操作的並行執行的,等到它們都執行完後纔會進到then裏面。那麼,三個異步操作返回的數據哪裏去了呢?都在then裏面呢,all會把所有異步操作的結果放進一個數組中傳給then,就是上面的results。 有了all,你就可以並行執行多個異步操作,並且在一個回調中處理所有的返回數據,是不是很酷?有一個場景是很適合用這個的,一些遊戲類的素材比較多的應用,打開網頁時,預先加載需要用到的各種資源如圖片、flash以及各種靜態文件。所有的都加載完後,我們再進行頁面的初始化。
function syncA(){
const P = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('執行syncA');
resolve('syncA-over')
})
})
return P;
}
function syncB(){
const P = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('執行syncB');
resolve('syncB-over')
})
})
return P;
}
function syncC(){
const P = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('執行syncC');
resolve('syncC-over')
})
})
return P;
}
Promise
.all([syncA(), syncB(), syncC()])
.then(function(results){
console.log(results);
})
輸出的結果爲:
Race的用法
race是 【誰跑的快,以誰爲準執行回調函數】
//請求某個圖片資源
function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'xxxxxx.jpg';
});
return p;
}
//延時函數,用於給請求計時
function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
reject('圖片請求超時');
}, 5000);
});
return p;
}
Promise.race([requestImg(),timeout()])
.then((results)=>{
console.log(results)
})
.catch((reason)=>{
console.log(reason)
})
requestImg函數會異步請求一張圖片,我把地址寫爲"xxxxxx",所以肯定是無法成功請求到的。timeout函數是一個延時5秒的異步操作。我們把這兩個返回Promise對象的函數放進race,於是他倆就會賽跑,如果5秒之內圖片請求成功了,那麼遍進入then方法,執行正常的流程。如果5秒鐘圖片還未成功返回,那麼timeout就跑贏了,則進入catch,報出“圖片請求超時”的信息。
補充
8.19:resolve是不接受多個參數的,如resolve(a,b)的時候,b將會被忽略。應改爲resolve([a,b])&&sync().then([a,b]),下面是微信羣裏分享的網易雲一面題目以及我的答案
function getValue (a, b) {
const P = new Promise((resolve) => {
setTimeout(() => {
resolve([a, b])
}, 2000)
})
return P
}
getValue(1, 2).then(([a, b]) => {
return a + b
})