lodash已死?Radash庫方法介紹及源碼解析 —— 異步方法篇

寫在前面
tips:點贊 + 收藏 = 學會!
- 我們前面已經介紹了
radash的相關信息和所有Array相關方法,詳情可前往主頁查看。 - 本篇我們繼續介紹radash中異步相關的方法。
- 所有方法分享完畢后,后續作者也會整理出
Radash庫所有方法的使用目錄,包括文章說明和腦圖說明。- 因為方法較多,后續將專門發布一篇總結文檔,方便大家查閱使用。
- 所有方法的思維導圖說明后續也會上傳至 github 和 gitee,有需要的可以訪問下載。
all:同時執行多個異步操作
- 使用說明
- 功能描述: 類似于
Promise.all和Promise.allSettled,等待一個由多個Promise組成的對象或數組中的所有Promise都完成(或者其中一個失敗)。執行的所有錯誤和拋出的錯誤都會收集在AggregateError中。 - 參數:promise對象/promise數組
- 返回值:所有
promise執行后的結果數組或對象
- 功能描述: 類似于
- 使用代碼示例
import { all } from 'radash' // 傳入promise數組 const [user] = await all([ api.users.create(...), s3.buckets.create(...), slack.customerSuccessChannel.sendMessage(...) ]) // 傳入對象 const { user } = await all({ user: api.users.create(...), bucket: s3.buckets.create(...), message: slack.customerSuccessChannel.sendMessage(...) }) - 源碼解析
// 定義一個泛型異步函數 `all`。 export async function all< // 泛型約束 `T` 可以是一個 `Promise` 數組或一個 `Promise` 對象。 T extends Record<string, Promise<any>> | Promise<any>[] >(promises: T) { // 根據 `promises` 是數組還是對象,將其轉換成一個統一格式的數組 `entries`。 const entries = isArray(promises) ? promises.map(p => [null, p] as [null, Promise<any>]) : Object.entries(promises) // 使用 `Promise.all` 等待所有 `Promise` 完成,并處理每個 `Promise` 的結果和異常。 const results = await Promise.all( entries.map(([key, value]) => value .then(result => ({ result, exc: null, key })) // 如果成功,記錄結果。 .catch(exc => ({ result: null, exc, key })) // 如果失敗,記錄異常。 ) ) // 篩選出所有出現異常的結果。 const exceptions = results.filter(r => r.exc) // 如果有異常,拋出一個 `AggregateError`,包含所有異常。 if (exceptions.length > 0) { throw new AggregateError(exceptions.map(e => e.exc)) } // 如果輸入的 `promises` 是數組,返回一個包含所有結果的數組。 if (isArray(promises)) { return results.map(r => r.result) as T extends Promise<any>[] ? PromiseValues<T> : unknown } // 如果輸入的 `promises` 是對象,將結果組合成一個新對象并返回。 return results.reduce( (acc, item) => ({ ...acc, [item.key!]: item.result // 使用斷言 `item.key!`,因為我們知道 `key` 不會是 `null`。 }), {} as { [K in keyof T]: Awaited<T[K]> } // 返回類型是一個對象,其鍵類型為 `T` 的鍵,值類型為 `T` 中 `Promise` 解析后的類型。 ) }- 方法流程說明:
- 將輸入的
promises轉換為一個統一格式的entries數組,無論它是一個Promise數組還是一個Promise對象。 - 對于每個
entry,創建一個新的Promise來處理成功和失敗的情況,并使用Promise.all等待所有這些新Promise完成。 - 如果所有
Promise都成功解析,根據promises是數組還是對象,返回一個包含所有結果的數組或對象。 - 如果有一個或多個
Promise失敗,則拋出一個AggregateError,其中包含所有失敗的Promise的異常。
- 將輸入的
- 方法流程說明:
defer:在異步流程中添加清理或錯誤處理邏輯
- 使用說明
- 功能描述:用來執行一個異步函數,同時提供注冊回調的機制,在異步函數執行完成后執行特定回調操作。
- 參數:異步函數。
- 返回值:異步函數成功執行時,返回其響應結果,否則重新拋出錯誤。
- 使用代碼示例
import { defer } from 'radash' await defer(async (cleanup) => { const buildDir = await createBuildDir() cleanup(() => fs.unlink(buildDir)) await build() }) await defer(async (register) => { const org = await api.org.create() register(async () => api.org.delete(org.id), { rethrow: true }) const user = await api.user.create() register(async () => api.users.delete(user.id), { rethrow: true }) await executeTest(org, user) }) - 源碼解析
// 定義一個異步泛型函數 `defer`。 export const defer = async <TResponse>( // `func` 是一個接受注冊函數 `register` 的異步函數。 func: ( register: ( // `register` 允許 `func` 注冊一個回調函數 `fn`,該函數在 `func` 執行完成后調用。 // 可以通過 `options` 指定是否在回調函數中重新拋出錯誤。 fn: (error?: any) => any, options?: { rethrow?: boolean } ) => void ) => Promise<TResponse> ): Promise<TResponse> => { // 初始化一個用于存放回調函數及其選項的數組 `callbacks`。 const callbacks: { fn: (error?: any) => any rethrow: boolean }[] = [] // 實現注冊函數 `register`,它將回調函數及其選項添加到 `callbacks` 數組。 const register = ( fn: (error?: any) => any, options?: { rethrow?: boolean } ) => callbacks.push({ fn, rethrow: options?.rethrow ?? false }) // 調用 `tryit` 函數執行 `func`,并傳入 `register`。 // `tryit` 函數不在提供的代碼片段中,但我們可以假設它是一個錯誤處理函數,返回一個包含錯誤和響應的元組。 const [err, response] = await tryit(func)(register) // 遍歷 `callbacks` 數組,依次執行每個回調函數。 for (const { fn, rethrow } of callbacks) { // 使用 `tryit` 函數調用回調,以捕獲并處理任何拋出的錯誤。 const [rethrown] = await tryit(fn)(err) // 如果回調函數中有錯誤被重新拋出,并且 `rethrow` 選項為 `true`,則重新拋出該錯誤。 if (rethrown && rethrow) throw rethrown } // 如果 `func` 執行時有錯誤產生,重新拋出該錯誤。 if (err) throw err // 如果 `func` 執行成功,返回響應結果。 return response }- 方法流程說明:
- 定義一個
callbacks數組來存儲注冊的回調函數及其選項。 - 實現
register函數,該函數允許func注冊回調函數和選項。 - 調用外部提供的(但在代碼片段中未定義)
tryit函數執行func,并傳遞register函數給func。 - 等待
func完成執行,獲取可能的錯誤err和響應response。 - 依次執行
callbacks數組中的回調函數,處理可能的錯誤。 - 如果任何一個回調函數中出現需要重新拋出的錯誤,并且其
rethrow選項為true,則重新拋出該錯誤。 - 如果
func執行時產生了錯誤,重新拋出該錯誤。 - 如果
func成功執行,返回其響應結果。
- 定義一個
- 方法流程說明:
guard:執行一個函數,并提供錯誤處理的能力
- 使用說明
- 功能描述:
guard函數可以用來為函數調用提供額外的錯誤處理邏輯,特別是當你希望根據錯誤類型選擇性地處理錯誤時。 - 參數:目標函數、指定錯誤對象得函數(可選)。
- 返回值:拋出原始或返回undefined。
- 功能描述:
- 使用代碼示例
import { guard } from 'radash' const users = (await guard(fetchUsers)) ?? [] const isInvalidUserError = (err: any) => err.code === 'INVALID_ID' const user = (await guard(fetchUser, isInvalidUserError)) ?? DEFAULT_USER - 源碼解析
// 定義一個泛型函數 `guard`。 export const guard = <TFunction extends () => any>( // 參數 `func` 是一個無參數的函數,它可能返回任何類型的值,包括 `Promise`。 func: TFunction, // 可選參數 `shouldGuard` 是一個函數,它接受一個錯誤對象 `err`, // 并返回一個布爾值,指示是否應該 "guard" 這個錯誤。 shouldGuard?: (err: any) => boolean // 函數的返回類型依賴于 `func` 的返回類型。如果 `func` 返回一個 `Promise`, // 則 `guard` 返回一個 `Promise`,該 `Promise` 解析為 `func` 的返回值或 `undefined`。 // 如果 `func` 不返回 `Promise`,則 `guard` 返回 `func` 的返回值或 `undefined`。 ): ReturnType<TFunction> extends Promise<any> ? Promise<Awaited<ReturnType<TFunction>> | undefined> : ReturnType<TFunction> | undefined => { // 定義一個內部函數 `_guard`,它接受一個錯誤對象 `err`。 const _guard = (err: any) => { // 如果提供了 `shouldGuard` 函數并且該函數返回 `false`, // 表示不應該 "guard" 這個錯誤,則重新拋出該錯誤。 if (shouldGuard && !shouldGuard(err)) throw err // 否則,返回 `undefined`。 return undefined as any } // 定義一個類型守衛函數 `isPromise`,它檢查一個值是否為 `Promise`。 const isPromise = (result: any): result is Promise<any> => result instanceof Promise try { // 嘗試執行 `func` 并獲取結果。 const result = func() // 如果 `result` 是一個 `Promise`,使用 `catch` 方法應用 `_guard` 函數。 // 否則,直接返回 `result`。 return isPromise(result) ? result.catch(_guard) : result } catch (err) { // 如果在執行 `func` 時拋出錯誤,使用 `_guard` 函數處理該錯誤。 return _guard(err) } }- 方法流程說明:
- 嘗試執行
func函數并捕獲任何拋出的錯誤。 - 如果
func執行成功并返回一個Promise,那么使用catch方法捕獲該Promise可能拋出的錯誤,并應用_guard函數。 - 如果
func執行成功并沒有返回Promise,那么直接返回結果。 - 如果
func拋出錯誤,應用_guard函數來決定是否重新拋出錯誤或返回undefined。 - 如果提供了
shouldGuard函數,它將用來判斷是否應該 "guard"(捕獲并返回undefined)錯誤。如果shouldGuard函數返回false,則拋出原始錯誤;如果返回true或未提供shouldGuard函數,則返回undefined。
- 嘗試執行
- 方法流程說明:
map:對一個數組中的每個元素執行一個異步映射函數
- 使用說明
- 功能描述:它用于對一個數組中的每個元素執行一個異步映射函數,并返回一個包含所有映射結果的新數組。這個函數是
Array.prototype.map方法的異步版本。 - 參數:數組,異步函數。
- 返回值:映射后的新數組。
- 功能描述:它用于對一個數組中的每個元素執行一個異步映射函數,并返回一個包含所有映射結果的新數組。這個函數是
- 使用代碼示例
import { map } from 'radash' const userIds = [1, 2, 3, 4] const users = await map(userIds, async (userId) => { return await api.users.find(userId) }) - 源碼解析
// 定義一個異步函數 `map`。 export const map = async <T, K>( // 第一個參數 `array` 是一個具有只讀屬性的泛型數組。 array: readonly T[], // 第二個參數 `asyncMapFunc` 是一個異步映射函數,它接受一個數組元素和它的索引, // 返回一個 `Promise`,該 `Promise` 解析為新類型 `K` 的值。 asyncMapFunc: (item: T, index: number) => Promise<K> ): Promise<K[]> => { // 如果傳入的數組 `array` 不存在,則返回一個空數組。 if (!array) return [] // 初始化一個空數組 `result`,用于存放映射后的新值。 let result = [] // 初始化一個索引計數器 `index`。 let index = 0 // 使用 `for...of` 循環遍歷數組 `array` 的每個元素。 for (const value of array) { // 對每個元素調用 `asyncMapFunc` 映射函數,并等待其 `Promise` 解析。 const newValue = await asyncMapFunc(value, index++) // 將解析后的新值添加到 `result` 數組中。 result.push(newValue) } // 循環完成后,返回包含所有新值的數組 `result`。 return result }- 方法流程說明:
- 檢查
array是否存在。如果不存在,返回一個空數組。 - 初始化一個空數組
result用于存儲映射結果,以及一個索引計數器index。 - 遍歷
array中的每個元素。 - 對于每個元素,調用異步映射函數
asyncMapFunc并等待Promise解析。 - 將異步映射函數解析后的結果添加到
result數組中。 - 在遍歷完所有元素之后,返回包含所有映射結果的
result數組。
- 檢查
- 方法流程說明:
parallel:并行地處理數組中的元素,并對每個元素執行一個異步函數
- 使用說明
- 功能描述:這個函數會限制同時進行的異步操作的數量,以避免同時啟動過多的異步任務。
- 參數:限制數量(number)、需要被異步處理的元素數組、轉換函數(將數組中的每個元素轉換為一個異步操作)。
- 返回值:返回一個數組,該數組包含了按原數組順序排序的所有成功的結果。
- 使用代碼示例
// 定義一個異步泛型函數 `parallel`。 export const parallel = async <T, K>( // `limit` 是一個數字,指定了可以同時運行的異步任務的最大數量。 limit: number, // `array` 是一個只讀數組,包含將要被異步處理的元素。 array: readonly T[], // `func` 是一個函數,將數組中的每個元素轉換為一個異步操作(返回 Promise)。 func: (item: T) => Promise<K> ): Promise<K[]> => { // 將數組 `array` 轉換為包含元素和它們索引的對象的數組 `work`。 const work = array.map((item, index) => ({ index, item })) // 定義一個處理函數 `processor`,它將異步處理 `work` 數組中的元素。 const processor = async (res: (value: WorkItemResult<K>[]) => void) => { const results: WorkItemResult<K>[] = [] while (true) { // 從 `work` 數組的末尾取出一個元素進行處理。 const next = work.pop() // 如果沒有更多元素,調用回調函數 `res` 并傳入結果數組 `results`。 if (!next) return res(results) // 使用 `tryit` 函數執行 `func` 并處理結果或錯誤。 const [error, result] = await tryit(func)(next.item) // 將結果或錯誤添加到 `results` 數組中。 results.push({ error, result: result as K, index: next.index }) } } // 創建一個 `queues` 數組,它包含了 `limit` 個新的 Promise,每個 Promise 都由 `processor` 函數處理。 const queues = list(1, limit).map(() => new Promise(processor)) // 使用 `Promise.all` 等待所有的 `queues` 中的 Promise 完成。 const itemResults = (await Promise.all(queues)) as WorkItemResult<K>[][] // 將所有的結果扁平化并根據索引排序,然后使用 `fork` 函數將結果分為錯誤和成功的結果。 const [errors, results] = fork( sort(itemResults.flat(), r => r.index), x => !!x.error ) // 如果有任何錯誤,拋出一個 `AggregateError` 包含所有錯誤。 if (errors.length > 0) { throw new AggregateError(errors.map(error => error.error)) } // 返回一個數組,它包含了按原數組順序排序的所有成功的結果。 return results.map(r => r.result) } - 源碼解析
// 定義一個異步泛型函數 `parallel`。 export const parallel = async <T, K>( // `limit` 是一個數字,指定了可以同時運行的異步任務的最大數量。 limit: number, // `array` 是一個只讀數組,包含將要被異步處理的元素。 array: readonly T[], // `func` 是一個函數,將數組中的每個元素轉換為一個異步操作(返回 Promise)。 func: (item: T) => Promise<K> ): Promise<K[]> => { // 將數組 `array` 轉換為包含元素和它們索引的對象的數組 `work`。 const work = array.map((item, index) => ({ index, item })) // 定義一個處理函數 `processor`,它將異步處理 `work` 數組中的元素。 const processor = async (res: (value: WorkItemResult<K>[]) => void) => { const results: WorkItemResult<K>[] = [] while (true) { // 從 `work` 數組的末尾取出一個元素進行處理。 const next = work.pop() // 如果沒有更多元素,調用回調函數 `res` 并傳入結果數組 `results`。 if (!next) return res(results) // 使用 `tryit` 函數執行 `func` 并處理結果或錯誤。 const [error, result] = await tryit(func)(next.item) // 將結果或錯誤添加到 `results` 數組中。 results.push({ error, result: result as K, index: next.index }) } } // 創建一個 `queues` 數組,它包含了 `limit` 個新的 Promise,每個 Promise 都由 `processor` 函數處理。 const queues = list(1, limit).map(() => new Promise(processor)) // 使用 `Promise.all` 等待所有的 `queues` 中的 Promise 完成。 const itemResults = (await Promise.all(queues)) as WorkItemResult<K>[][] // 將所有的結果扁平化并根據索引排序,然后使用 `fork` 函數將結果分為錯誤和成功的結果。 const [errors, results] = fork( sort(itemResults.flat(), r => r.index), x => !!x.error ) // 如果有任何錯誤,拋出一個 `AggregateError` 包含所有錯誤。 if (errors.length > 0) { throw new AggregateError(errors.map(error => error.error)) } // 返回一個數組,它包含了按原數組順序排序的所有成功的結果。 return results.map(r => r.result) }- 這段代碼中使用了幾個未定義的函數和類型,如
tryit、list、fork和sort,以及類型WorkItemResult<K>。我們可以假設這些函數和類型具有以下功能:tryit(func)(item):執行func(item)并捕獲任何拋出的錯誤,返回一個包含錯誤和結果的元組。list(1, limit):創建一個包含從 1 到limit的數字的數組。fork(array, condition):分割數組array,根據condition函數返回的布爾值將數組分為包含錯誤的元素和成功的元素兩個數組。sort(array, keySelector):根據keySelector函數返回的鍵對數組array進行排序。WorkItemResult<K>:一個類型,表示工作項的結果,包含可能的error、成功的result以及元素的index。
- 這段代碼中使用了幾個未定義的函數和類型,如
reduce:對數組中的每個元素執行一個異步歸約函數
- 使用說明
- 功能描述:它是
Array.prototype.reduce方法的異步版本,用于對數組中的每個元素執行一個異步歸約函數,并返回最終的歸約值。 - 參數:被歸約處理的元素數組、異步歸約函數。
- 返回值:返回最終歸約的值。
- 功能描述:它是
- 使用代碼示例
import { reduce } from 'radash' const userIds = [1, 2, 3, 4] const users = await reduce(userIds, async (acc, userId) => { const user = await api.users.find(userId) return { ...acc, [userId]: user } }, {}) - 源碼解析
// 定義一個異步泛型函數 `reduce`。 export const reduce = async <T, K>( // 第一個參數 `array` 是一個只讀數組,包含將要被歸約處理的元素。 array: readonly T[], // 第二個參數 `asyncReducer` 是一個異步歸約函數,它接受累加值 `acc`、當前元素 `item` 和它的索引 `index`, // 并返回一個 `Promise`,該 `Promise` 解析為新的累加值。 asyncReducer: (acc: K, item: T, index: number) => Promise<K>, // 第三個參數 `initValue` 是可選的初始值。 initValue?: K ): Promise<K> => { // 檢查初始值是否提供了。 const initProvided = initValue !== undefined // 如果沒有提供初始值且數組為空,則拋出錯誤。 if (!initProvided && array?.length < 1) { throw new Error('Cannot reduce empty array with no init value') } // 如果提供了初始值,使用整個數組;否則,從數組的第二個元素開始迭代。 const iter = initProvided ? array : array.slice(1) // 初始化累加值 `value`。如果提供了初始值,使用它;否則使用數組的第一個元素。 let value: any = initProvided ? initValue : array[0] // 使用 `for...of` 循環和 `entries` 方法遍歷數組或其子數組。 for (const [i, item] of iter.entries()) { // 對每個元素調用異步歸約函數 `asyncReducer` 并等待其 `Promise` 解析。 value = await asyncReducer(value, item, i) } // 循環完成后,返回最終的累加值 `value`。 return value }- 方法流程說明:
- 檢查是否提供了初始值
initValue。 - 如果沒有提供初始值且數組為空,則拋出錯誤,因為無法從空數組中歸約出一個值。
- 確定迭代的數組。如果提供了初始值,則迭代整個數組;如果沒有提供初始值,則從數組的第二個元素開始迭代。
- 初始化累加值
value。如果提供了初始值,則使用該初始值;如果沒有提供初始值,則使用數組的第一個元素作為初始累加值。 - 遍歷數組,對每個元素調用異步歸約函數
asyncReducer,并等待其返回的Promise解析。 - 更新累加值
value為asyncReducer返回的新值。 - 在遍歷完所有元素之后,返回最終的累加值。
- 檢查是否提供了初始值
- 方法流程說明:
retry:反復嘗試執行一個異步操作,直到達到設置上限
- 使用說明
- 功能描述:用于反復嘗試執行一個異步操作,直到成功或達到重試次數上限。如果操作失敗,可以選擇在重試之間設置延遲或使用退避函數(backoff)來計算延遲時間。
- 參數:條件對象options(包含:重復次數、延遲、退避函數)、失敗執行的異步操作函數。
- 返回值:可能發揮undefined。
- 使用代碼示例
import { retry } from 'radash' await retry({}, api.users.list) await retry({ times: 10 }, api.users.list) await retry({ times: 2, delay: 1000 }, api.users.list) // exponential backoff await retry({ backoff: i => 10**i }, api.users.list) - 源碼解析
// 定義一個異步泛型函數 `retry`。 export const retry = async <TResponse>( // `options` 對象包含重試策略的選項。 options: { times?: number // 重試次數,默認為 3。 delay?: number | null // 固定延遲時間,如果提供,則在重試之間等待這么多毫秒。 backoff?: (count: number) => number // 退避函數,可以根據重試次數來計算延遲時間。 }, // `func` 是要執行的異步函數,它可能會失敗。 func: (exit: (err: any) => void) => Promise<TResponse> ): Promise<TResponse> => { // 從 `options` 中獲取重試次數、固定延遲時間和退避函數。 const times = options?.times ?? 3 const delay = options?.delay const backoff = options?.backoff ?? null // 使用 `range` 函數生成一個序列,并遍歷這個序列進行重試。 for (const i of range(1, times)) { // 嘗試執行 `func` 函數,并捕獲可能的錯誤 `err` 和結果 `result`。 const [err, result] = (await tryit(func)((err: any) => { // 如果 `func` 失敗,并使用 `exit` 函數退出,則拋出一個特殊的錯誤對象。 throw { _exited: err } })) as [any, TResponse] // 如果沒有錯誤,說明 `func` 成功執行,返回結果。 if (!err) return result // 如果有特殊的退出錯誤,重新拋出原始錯誤。 if (err._exited) throw err._exited // 如果是最后一次重試且仍然失敗,拋出錯誤。 if (i === times) throw err // 如果設置了固定延遲時間,使用 `sleep` 函數等待。 if (delay) await sleep(delay) // 如果提供了退避函數,根據重試次數計算延遲時間并等待。 if (backoff) await sleep(backoff(i)) } // 如果代碼執行到這里,說明邏輯上不應該到達的代碼路徑。 // 這是為了滿足 TypeScript 的嚴格模式要求。 /* istanbul ignore next */ return undefined as unknown as TResponse }- 方法流程說明:
- 從
options中獲取重試次數、延遲和退避函數。 - 遍歷從 1 到重試次數的范圍。
- 在每次迭代中,嘗試執行
func并捕獲可能的錯誤和結果。 - 如果
func成功執行(沒有錯誤),返回結果。 - 如果有錯誤,并且是通過
exit函數顯式退出的,重新拋出原始錯誤。 - 如果達到了重試次數上限并且仍然失敗,拋出最后一次的錯誤。
- 如果指定了延遲或退避函數,根據相應的策略等待一段時間后再重試。
- 如果執行到函數的末尾,返回
undefined作為占位符,因為邏輯上不應該到達這里。
- 從
- 方法流程說明:
sleep:提供一個延時機制
- 使用說明
- 功能描述:提供一個延時機制,通常用于異步操作中的暫停。
- 參數:暫停時間(ms)。
- 返回值:返回一個新的Promise。
- 使用代碼示例
import { sleep } from 'radash' await sleep(2000) // => waits 2 seconds - 源碼解析
// 定義一個名為 `sleep` 的函數。 export const sleep = (milliseconds: number) => { // 返回一個新的 Promise。 return new Promise(res => // 使用 `setTimeout` 函數設置一個定時器,它在 `milliseconds` 指定的毫秒數后執行。 setTimeout( // 當定時器到時,調用 `res` 函數來解析這個 Promise。 res, // 傳遞給 `setTimeout` 的毫秒數,它決定了延時的長度。 milliseconds ) ) }- 方法流程說明:當你調用
sleep函數并傳入一個毫秒數時,它會返回一個Promise。這個Promise不會立即解析,而是會等待你指定的時間長度。當時間到了之后,Promise會被解析,然后你可以在.then()方法中繼續執行后續的代碼,或者你可以在async函數中使用await關鍵字來等待Promise解析。
- 方法流程說明:當你調用
tryit:捕獲函數在執行過程中可能拋出的同步或異步錯誤
- 使用說明
- 功能描述:
tryit是一個高階函數。用于捕獲函數在執行過程中可能拋出的同步或異步錯誤,并返回一個元組,其中包含錯誤對象或函數的返回值。這個函數的目的是提供一種安全執行任意函數并處理錯誤的方式。 - 參數:需要被捕獲的函數。
- 返回值:返回一個新函數,該函數接收與傳入函數相同的參數。
- 功能描述:
- 使用代碼示例
import { tryit } from 'radash' const findUser = tryit(api.users.find) const [err, user] = await findUser(userId) - 源碼解析
// 定義一個泛型高階函數 `tryit`。 export const tryit = <Args extends any[], Return>( // `func` 是一個接受任意參數的函數,其返回值可以是任何類型,包括 `Promise`。 func: (...args: Args) => Return ) => { // 返回一個新函數,這個新函數接受與 `func` 相同的參數。 return ( ...args: Args // 新函數的返回類型取決于 `func` 的返回類型是否是 `Promise`。 // 如果 `func` 返回 `Promise`,則返回一個 `Promise`,包含一個錯誤或函數返回值的元組。 // 如果 `func` 返回非 `Promise`,則直接返回錯誤或函數返回值的元組。 ): Return extends Promise<any> ? Promise<[Error, undefined] | [undefined, Awaited<Return>]> : [Error, undefined] | [undefined, Return] => { try { // 嘗試執行 `func` 并獲取結果。 const result = func(...args) // 使用輔助函數 `isPromise` 檢查 `result` 是否是 `Promise`。 if (isPromise(result)) { // 如果是 `Promise`,使用 `then` 和 `catch` 方法處理結果或捕獲錯誤。 return result .then(value => [undefined, value]) // 成功時返回值的元組。 .catch(err => [err, undefined]) // 錯誤時返回錯誤的元組。 } // 如果 `result` 不是 `Promise`,直接返回值的元組。 return [undefined, result] } catch (err) { // 如果執行 `func` 時捕獲到同步錯誤,返回錯誤的元組。 return [err as any, undefined] } } }- 方法流程說明:
tryit函數接受一個函數func作為參數。tryit返回一個新函數,這個新函數接受與func相同的參數。- 當調用這個新函數時,它嘗試執行
func。 - 如果
func成功執行,且其返回值不是Promise,新函數返回一個元組[undefined, result]。 - 如果
func返回一個Promise,新函數返回一個Promise,該Promise解析為元組[undefined, value]或[err, undefined],具體取決于Promise是成功解析還是被拒絕。 - 如果在執行
func時捕獲到同步錯誤,新函數返回一個元組[err, undefined]。 - 如果
func的返回類型是Promise,那么新函數的返回類型也是Promise,否則返回類型就是元組。
- 方法流程說明:
寫在后面
- 后續我們會繼續分享
Radash庫中其他方法的使用和源碼解析。 - 大家有任何問題或見解,歡迎評論區留言交流和批評指正!!!
- 你的每一個點贊和收藏都是作者寫作的動力!!!
- 點擊訪問:radash官網

浙公網安備 33010602011771號