再次梳理一下同步和異步的差別:
同步:在執行一段代碼,沒有傳回結果之前,則不執行後面的代碼。會阻塞後面代碼的執行。
異步:與同步執行相反,在執行執行一段代碼沒有傳回結果時,通過一個回調函數來處理這個結果,繼續執行後面的代碼。
在ES6中,用Promise對象來表示異步的最終完成和結果。
Promise以下三個狀态:
待定(pending): 初始狀态。
已兌現(fulfilled): 意味着操作成功完成。
已拒絕(rejected): 意味着操作失敗。
pending狀态要麼轉化為fulfilled,要麼轉化為rejected狀态,通過promise的then方法和catch方法來傳回對應的promise對象。
const fs = require("fs")
let readFilePromise = (filename) => {
return new Promise((resolve,) => {
fs.readFile(filename, (err,) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}
readFilePromise('./fs.json').then(res => {
console.log("res", res)
})
每次任務執行結束後産生的失敗是直接被catch捕捉到的,因為Promise采用的是錯誤冒泡的方式,産生的錯誤會一直往後傳遞,直到被catch捕獲。這樣我們就不用頻繁的檢查錯誤了。
這就是Promise的好處:通過鍊式調用的方式來解決了多層嵌套的問題;Promise通過錯誤冒泡來統一做錯誤處理,這樣避免每個任務都要錯誤檢查導緻代碼混亂的問題。
Promise靜态方法
Promise.all
參數是可疊代的對象,比如數組,Promise.all是把多個異步操作并行執行,所有的異步都成功後才傳回成功,傳回的值也是按照入參的順序來傳回。如果有一個異步失敗,就傳回失敗,會把第一個異步失敗當成Promise.all的失敗結果傳回。
//1.擷取輪播資料清單
function getBannerList() {
return new Promise((resolve,) => {
setTimeout(function () {
resolve('banner')
}, 300)
})
}
//2.擷取店鋪清單
function getStoreList() {
return new Promise((resolve,) => {
setTimeout(function () {
resolve('store')
}, 500)
})
}
//3.擷取分類清單
function getCategoryList() {
return new Promise((resolve,) => {
setTimeout(function () {
reject("失敗了")
// resolve('category')
}, 700)
})
}
function initLoad() {
Promise.all([getBannerList(), getStoreList(), getCategoryList()])
.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
}
initLoad()
Promise.allSettled
和Promise.all相似,傳回一個對象數組,每個對象表示對應的異步任務的結果,不管異步任務的結果fulfilled還是reject。
Promise.allSettled适合多個彼此不依賴的異步任務,Promise.all更合适多個互相依賴的異步任務。
對之前的案例代碼稍微改造一下:
function initLoad() {
Promise.allSettled([getBannerList(), getStoreList(), getCategoryList()])
.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
}
initLoad(); // [{ status: 'fulfilled', value: 'banner' },{ status: 'fulfilled', value: 'store' },{ status: 'rejected', reason: '失敗了' }]
Promise.any
傳入一個可疊代的參數,如數組。
傳回已經成功的異步任務,如果有多個異步都fulfilled了的,那就傳回第一個。如果所有的參數都變成rejected的話,那麼就傳回一個rejected。
//1.擷取輪播資料清單
function getBannerList() {
return new Promise((resolve,) => {
setTimeout(function () {
reject('banner')
}, 300)
})
}
//2.擷取店鋪清單
function getStoreList() {
return new Promise((resolve,) => {
setTimeout(function () {
reject('store')
}, 500)
})
}
//3.擷取分類清單
function getCategoryList() {
return new Promise((resolve,) => {
setTimeout(function () {
reject("失敗了")
// resolve('category')
}, 700)
})
}
function initLoad() {
Promise.any([getBannerList(), getStoreList(), getCategoryList()])
.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
}
initLoad(); // [AggregateError: All promises were rejected]
Promise.race