lodash已死?Radash库方法介绍及源码解析 —— 异步方法篇

2024-05-15 18:36

本文主要是介绍lodash已死?Radash库方法介绍及源码解析 —— 异步方法篇,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

all:同时执行多个异步操作

  1. 使用说明

  • 功能描述: 类似于 Promise.all 和 Promise.allSettled,等待一个由多个 Promise 组成的对象或数组中的所有 Promise 都完成(或者其中一个失败)。执行的所有错误和抛出的错误都会收集在 AggregateError 中。

  • 参数:promise对象/promise数组

  • 返回值:所有 promise 执行后的结果数组或对象

  1. 使用代码示例

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(...)
})

  1. 源码解析

// 定义一个泛型异步函数 `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:在异步流程中添加清理或错误处理逻辑

  1. 使用说明

  • 功能描述:用来执行一个异步函数,同时提供注册回调的机制,在异步函数执行完成后执行特定回调操作。

  • 参数:异步函数。

  • 返回值:异步函数成功执行时,返回其响应结果,否则重新抛出错误。

  1. 使用代码示例

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)
})

  1. 源码解析

// 定义一个异步泛型函数 `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) => anyrethrow: 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:执行一个函数,并提供错误处理的能力

  1. 使用说明

  • 功能描述:guard 函数可以用来为函数调用提供额外的错误处理逻辑,特别是当你希望根据错误类型选择性地处理错误时。

  • 参数:目标函数、指定错误对象得函数(可选)。

  • 返回值:抛出原始或返回undefined。

  1. 使用代码示例

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

  1. 源码解析

// 定义一个泛型函数 `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 Promisetry {// 尝试执行 `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:对一个数组中的每个元素执行一个异步映射函数

  1. 使用说明

  • 功能描述:它用于对一个数组中的每个元素执行一个异步映射函数,并返回一个包含所有映射结果的新数组。这个函数是 Array.prototype.map 方法的异步版本。

  • 参数:数组,异步函数。

  • 返回值:映射后的新数组。

  1. 使用代码示例

import { map } from 'radash'const userIds = [1, 2, 3, 4]const users = await map(userIds, async (userId) => {return await api.users.find(userId)
})

  1. 源码解析

// 定义一个异步函数 `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:并行地处理数组中的元素,并对每个元素执行一个异步函数

  1. 使用说明

  • 功能描述:这个函数会限制同时进行的异步操作的数量,以避免同时启动过多的异步任务。

  • 参数:限制数量(number)、需要被异步处理的元素数组、转换函数(将数组中的每个元素转换为一个异步操作)。

  • 返回值:返回一个数组,该数组包含了按原数组顺序排序的所有成功的结果。

  1. 使用代码示例

// 定义一个异步泛型函数 `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)
}

  1. 源码解析

// 定义一个异步泛型函数 `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)
}

  • 这段代码中使用了几个未定义的函数和类型,如 tryitlistfork 和 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:对数组中的每个元素执行一个异步归约函数

  1. 使用说明

  • 功能描述:它是 Array.prototype.reduce 方法的异步版本,用于对数组中的每个元素执行一个异步归约函数,并返回最终的归约值。

  • 参数:被归约处理的元素数组、异步归约函数。

  • 返回值:返回最终归约的值。

  1. 使用代码示例

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}
}, {})

  1. 源码解析

// 定义一个异步泛型函数 `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:反复尝试执行一个异步操作,直到达到设置上限

  1. 使用说明

  • 功能描述:用于反复尝试执行一个异步操作,直到成功或达到重试次数上限。如果操作失败,可以选择在重试之间设置延迟或使用退避函数(backoff)来计算延迟时间。

  • 参数:条件对象options(包含:重复次数、延迟、退避函数)、失败执行的异步操作函数。

  • 返回值:可能发挥undefined。

  1. 使用代码示例

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)

  1. 源码解析

// 定义一个异步泛型函数 `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 ?? 3const delay = options?.delayconst 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:提供一个延时机制

  1. 使用说明

  • 功能描述:提供一个延时机制,通常用于异步操作中的暂停。

  • 参数:暂停时间(ms)。

  • 返回值:返回一个新的Promise。

  1. 使用代码示例

import { sleep } from 'radash'await sleep(2000) // => waits 2 seconds

  1. 源码解析

// 定义一个名为 `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:捕获函数在执行过程中可能抛出的同步或异步错误

  1. 使用说明

  • 功能描述:tryit 是一个高阶函数。用于捕获函数在执行过程中可能抛出的同步或异步错误,并返回一个元组,其中包含错误对象或函数的返回值。这个函数的目的是提供一种安全执行任意函数并处理错误的方式。

  • 参数:需要被捕获的函数。

  • 返回值:返回一个新函数,该函数接收与传入函数相同的参数。

  1. 使用代码示例

import { tryit } from 'radash'const findUser = tryit(api.users.find)const [err, user] = await findUser(userId)

  1. 源码解析

// 定义一个泛型高阶函数 `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,否则返回类型就是元组。

文章转载自:雾散声声慢

原文链接:https://www.cnblogs.com/muqiqiang/p/18190575

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

这篇关于lodash已死?Radash库方法介绍及源码解析 —— 异步方法篇的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/992603

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

浅谈主机加固,六种有效的主机加固方法

在数字化时代,数据的价值不言而喻,但随之而来的安全威胁也日益严峻。从勒索病毒到内部泄露,企业的数据安全面临着前所未有的挑战。为了应对这些挑战,一种全新的主机加固解决方案应运而生。 MCK主机加固解决方案,采用先进的安全容器中间件技术,构建起一套内核级的纵深立体防护体系。这一体系突破了传统安全防护的局限,即使在管理员权限被恶意利用的情况下,也能确保服务器的安全稳定运行。 普适主机加固措施:

webm怎么转换成mp4?这几种方法超多人在用!

webm怎么转换成mp4?WebM作为一种新兴的视频编码格式,近年来逐渐进入大众视野,其背后承载着诸多优势,但同时也伴随着不容忽视的局限性,首要挑战在于其兼容性边界,尽管WebM已广泛适应于众多网站与软件平台,但在特定应用环境或老旧设备上,其兼容难题依旧凸显,为用户体验带来不便,再者,WebM格式的非普适性也体现在编辑流程上,由于它并非行业内的通用标准,编辑过程中可能会遭遇格式不兼容的障碍,导致操

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}