Promise 是非同步編程的一種解決方案,比傳統的回調函數或事件更合理和更靈活。 Promise 方法 Promise的原型方法:then/catch/finally,這三種方法很常用,then用於處理Promise轉為fulfilled狀態時的代碼,catch用於處理Promise轉為reject ...
Promise 是非同步編程的一種解決方案,比傳統的回調函數或事件更合理和更靈活。
Promise 方法
Promise的原型方法:then/catch/finally,這三種方法很常用,then
用於處理Promise轉為fulfilled
狀態時的代碼,catch
用於處理Promise轉為rejected
狀態時的代碼(當然then
的第二個參數也可處理rejected
狀態),而finally
用於不管Promise狀態怎樣轉換都會最終執行的代碼。
promise的then方法的第二個參數和catch方法都可以處理rejected狀態,但它們之間有一些區別:
then的第二個參數只能處理當前的promise,而catch方法可以處理任意位置的rejected狀態。所以,如果多個then方法鏈式調用中有多個rejected狀態,可以在最後使用一個catch方法來處理。
then的第二個參數和catch方法的返回值不同。then的第二個參數返回的是一個新的promise對象,而catch方法返回的是一個值或一個新的promise對象。如果返回的是一個值,則會被自動包裝成一個resolved狀態的promise。
catch方法比then的第二個參數更簡潔,更易讀。因為catch方法只處理rejected狀態,而then方法需要在第一個參數中同時處理resolved和rejected狀態。
Promise的靜態方法: Promise.all、Promise.allSettled、Promise.any、Promise.race、Promise.resolve、Promise.reject。
Promise 靜態方法
Promise.resolve和Promise.reject用於一開始就創建 fulfilled
或rejected
狀態的Promise,其他的靜態方法傳參是Promise實例數組,差異在於處理實例數組的方式和結果。
Promise.all
並行執行多個Promise對象,併在所有Promise對象都成功時返回一個新的Promise對象,其resolve值為一個包含所有Promise結果的數組,如果其中一個Promise對象失敗,則返回一個reject的Promise對象,其值為第一個失敗的Promise的reject值。
;(async () => {
const promise1 = Promise.resolve('Hello')
const promise2 = 42
// const promise2 = Promise.reject('Error')
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'Goodbye')
})
// const promise4 = Promise.reject('Error2')
try {
const result = await Promise.all([promise1, promise2, promise3])
// 成功輸出:[ 'Hello', 42, 'Goodbye' ]
console.log(result)
} catch (e) {
// 失敗輸出:Error
console.log(e)
}
})()
Promise.allSettled
並行執行多個Promise對象,返回一個新的Promise對象(狀態一定是fulfilled),其resolve值為一個包含所有Promise結果的數組,其中每個元素都是對象,包含Promise對象的狀態和結果。
;(async () => {
const promise1 = Promise.resolve('Hello')
const promise2 = 42
// const promise2 = Promise.reject('Error')
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'Goodbye')
})
// const promise4 = Promise.reject('Error2')
try {
const result = await Promise.allSettled([promise1, promise2, promise3])
// 成功輸出:
// [
// { status: 'fulfilled', value: 'Hello' },
// { status: 'fulfilled', value: 42 },
// { status: 'fulfilled', value: 'Goodbye' }
// ]
console.log(result)
// 失敗輸出:
// [
// { status: 'fulfilled', value: 'Hello' },
// { status: 'rejected', reason: 'Error' },
// { status: 'fulfilled', value: 'Goodbye' }
// ]
} catch(e) {
// 不會執行
console.log('error:', e)
}
Promise.allSettled([promise1, promise2, promise3]).then((result) => {
// 成功輸出:
// [
// { status: 'fulfilled', value: 'Hello' },
// { status: 'fulfilled', value: 42 },
// { status: 'fulfilled', value: 'Goodbye' }
// ]
console.log(result)
// 失敗輸出:
// [
// { status: 'fulfilled', value: 'Hello' },
// { status: 'rejected', reason: 'Error' },
// { status: 'fulfilled', value: 'Goodbye' }
// ]
})
})()
Promise.all和Promise.allSettled的區別:
- Promise.all方法返回的一個Promise對象狀態將取決於所有Promise對象的狀態。如果其中有任何一個Promise對象被rejected了,那麼這個新的Promise對象也會被rejected,並且它的值為第一個被rejected的那個Promise對象的值。
- Promise.allSettled方法返回的一個Promise對象狀態一定是fulfilled。這個返回的Promise對象的值是一個數組,數組中包含了所有Promise對象的狀態和值信息。即便其中有任何一個Promise對象被rejected了,也不會影響這個新的Promise對象的狀態。
- 錯誤處理方面,Promise.all只能捕獲處理第一個錯誤狀態,如果需要處理所有狀態需要改造(如:每個promise設置catch處理、同步請求/非同步等待)或者使用 Promise.allSettled,具體需要怎麼做看自己的需求
Promise.any
並行執行多個Promise對象,並返回一個新的Promise對象,其resolve值為第一個成功的Promise對象的resolve值,如果所有Promise對象都失敗,則返回一個reject的Promise對象,其值為一個AggregateError對象,其中包含所有Promise對象的reject值。
const promise1 = Promise.reject("error1")
const promise2 = Promise.reject("error2")
const promise3 = Promise.resolve("success")
// const promise3 = Promise.reject("error3")
Promise.any([promise1, promise2, promise3]).then((value) => {
// 成功輸出:success
console.log(value)
}).catch((error) => {
// 失敗輸出:
// [AggregateError: All promises were rejected] {
// [errors]: [ 'error1', 'error2', 'error3' ]
// }
console.log(error)
})
Promise.race
並行執行多個Promise對象,並返回一個新的Promise對象,其resolve值為第一個完成的Promise對象的resolve值,如果所有Promise對象都失敗,則返回一個reject的Promise對象,其值為第一個失敗的Promise的reject值。
const promise1 = Promise.reject("error1")
const promise2 = Promise.reject("error2")
const promise3 = Promise.resolve("success")
// const promise3 = Promise.reject("error3")
Promise.race([promise1, promise2, promise3]).then((value) => {
// 成功輸出:error1
console.log(value)
}).catch((error) => {
// 失敗輸出:error1
console.log(error)
})
Promise.race和Promise.any的區別:
Promise.race會在其中任意一個Promise對象狀態改變(即fulfilled或rejected)時立即返回結果,而Promise.any只會在其中任意一個Promise對象fulfilled時返回結果。
當所有Promise對象都被rejected時,Promise.race會返回被rejected的Promise對象的結果,而Promise.any會拋出AggregateError異常。
如果Promise.race傳入的參數是空數組,它會一直處於pending狀態,而Promise.any會立即拋出AggregateError異常。(另外:Promise.all和Promise.allSettled返回fulfilled狀態)
使用Promise實現站點預檢
這是前幾天實現的站點預檢:判斷所有網站鏈接是否有效,並返回測試的結果。思路:通過get請求測試,考慮請求之間沒有關聯、錯誤處理方面最終選擇Promise.allSettled
,代碼如下:
// 實現 對多個網站鏈接預檢,判定網站鏈接是否有效
import { get } from 'https'
import { get as getHttp } from 'http'
import { URL } from 'url'
import { ATagSites } from '@/type'
export const detectSitesValid = (allSites: ATagSites[]) => {
// 遍歷 allSites 數組,獲取所有網站的鏈接
const sites: { name: string; url: string }[] = []
allSites.forEach((aTagSites) => {
aTagSites.sites.forEach((site) => {
sites.push({
name: site.name,
url: site.link
})
})
})
// 存儲所有網站的請求
const fetchRequests: Promise<string>[] = []
// 存儲請求結果
const fetchResults: string[] = []
// 遍歷所有網站,發起請求
sites.forEach((site) => {
const { name, url } = site
const { protocol } = new URL(url)
const request = protocol === 'https:' ? get : getHttp
fetchRequests.push(
new Promise((resolve, reject) => {
request(
{
hostname: new URL(url).hostname,
path: new URL(url).pathname,
method: 'GET',
timeout: 30000
},
(res) => {
const { statusCode, statusMessage } = res
fetchResults.push(`${name}, ${url}, ${statusCode || 200}, ${statusMessage || 'OK'}`)
resolve('ok')
}
).on('error', (err) => {
const { message } = err
fetchResults.push(`${name}, ${url}, ${0}, ${message}`)
resolve('error')
})
})
)
})
return Promise.allSettled(fetchRequests)
}