函数工具
import { <函数名称> } from "flex-tools/func"appleParams
包装一个函数,使得函数默认调用指定的参数。
function add(a:number,b:number){
return a + b;
}
let fn = appleParams(add,1,1)
fn() // == add(1,1)timeout
包装一个异步函数,使得该函数具备执行超时功能。
timeout(fn:AsyncFunction, options:{value?:number,default?:any}={}):AsyncFunction说明
value参数用来指定超时时间default参数用来指定当超时时默认返回的值。- 如果没有提供
default参数,则会触发TimeoutError。
memorize
包装一个函数记住最近一次调用的结果。
function (fn:Function,options:{hash?:((args: any[]) => string) | 'length' | boolean,expires?:number}={hash:false,expires:0})说明
hash=false时memorize无效。hash=true时,会记住最近一次调用的结果。hash='length'时,会记住最近一次调用的结构,当调用参数数量变化多端时,memorize失效。hash=(args: any[]) => string时,可以通过动态计算出hash值来决定memorize是否有效。
noReentry
包装异步函数禁止重入。
function (fn:Function,options?:{silence?:boolean})retry
包装异步函数使得具备出错重试功能。
function retry(this:any,fn: Function, options:{count?:number,interval?:number,default?:any}):AsyncFunction说明
count参数指重试次数interval参数指重试间隔default指出错并重试后返回的默认值。- 当被包装函数触发以
Signal结尾的错误时,则代表这不是一个一错误,而是一个向上传递的信号,不需要再进行重试
示例
async function getData(){
throw new Error()
}
let fn = retry(getData,{count:3,interval:1000})
class AbortSignal extends Error{}
async function getData(){
throw new AbortSignal()
}
let fn = retry(getData,{count:3,interval:1000})
fn() // 触发的错误是以Signal结尾的,所以不会重试reliable
包装一个函数使之同时具备retry、timeout、noReentry、memorize等功能。
type reliableOptions={
timeout : number, // 执行失败超时,默认为1秒
retryCount : number, // 重试次数
retryInterval : number, // 重试间隔
noReentry : boolean, // 不可重入
memorize : ((args: any[]) => string) | 'length' | boolean
}
function reliable(fn:AsyncFunction,options:reliableOptions):AsyncFunctionsafeCall
安全执行函数并对错误进行捕获,不会抛出异常。用于执行一些函数的时候不希望抛出异常。
export function safeCall(fn:Function,args?:any[]):any;
export function safeCall(fn:Function,options?:SafeCallOptions | SafeCallCatcher):any;
export function safeCall(fn:Function,args?:any[] | SafeCallOptions | SafeCallCatcher,options?:SafeCallOptions | SafeCallCatcher):any
safeCall(fn) // 相当于 try{fn()}catch(e){}
safeCall(fn,[1,2]) // 相当于 try{fn(1,2)}catch(e){}
safeCall(fn,{catch:'throw'}) // 相当于 try{fn()}catch(e){throw e}
safeCall(fn,{catch:'ignore'}) // 相当于 try{fn()}catch(e){}
safeCall(fn,{catch:'throw',error:new MyError()}) // 相当于 try{fn()}catch(e){throw MyError}
safeCall(fn,[1,2],{default:100}) // 相当于 try{fn(1,2)}catch(e){return 100}
safeCall(fn,{default:100}) // 相当于 try{fn()}catch(e){return 100}
safeCall(fn,(e)=>1) // 相当于 try{fn()}catch(e){return (e)=>1}
// 支持异步函数
await safeCall(asyncFn) // 相当于 try{ await asyncFn()}catch(e){}
await safeCall(asyncFn,[1,2]) // 相当于 try{ await asyncFn(1,2)}catch(e){}
await safeCall(asyncFn,{catch:'throw'}) // 相当于 try{ await asyncFn()}catch(e){throw e}
await safeCall(asyncFn,{catch:'ignore'}) // 相当于 try{ await asyncFn()}catch(e){}
await safeCall(asyncFn,[1,2],{default:100}) // 相当于 try{ await asyncFn(1,2)}catch(e){return 100}
await safeCall(asyncFn,{default:100}) // 相当于 try{ await asyncFn()}catch(e){return 100}
await safeCall(asyncFn,(e)=>1) // 相当于 try{ await asyncFn()}catch(e){return (e)=>1}promisify
用来将一个依赖回调异步函数转换为一个返回promise的异步函数。
类似功能的库很多,比如util.promisify,pify,thenify等等。
- 包装nodejs标准库的异步函数
nodejs标准库的异步函数特点是callback的最后一个参数是一个回调函数,该回调函数的第一个参数是错误对象,如果没有错误则为null。
import fs from "node:fs"
const readFile = promisify(fs.readFile)
readFile("./timer.ts").then((content)=>{
console.log("content:",String(content))
})- 包装任意函数
支持包括任意异步函数。需要提供buildArgs和parseCallback两个函数来处理参数和回调。
function sum(callback:(x:number,y:number,z:number)=>void,a:number,b:number){
if(a==0 && b==0) throw new Error("a and b can not be 0")
callback(a,b,a+b)
}
const promisifySum = promisify(sum,{
buildArgs:(args:any[],callback)=>{
return [callback,...args]
},
parseCallback:(results:any[])=>{
return results
}
})
console.log(await promisifySum(1,2)) // [ 1, 2, 3 ]
try{
await promisifySum(0,0)
}catch(e){
console.log(e.message) // a and b can not be 0
}buildArgs(args:any[],callback)参数用来指定一个函数将异步函数的参数转换为原始函数的参数。比如上例中,sum函数的原始签名是sum(callback:(x:number,y:number,z:number)=>void,a:number,b:number),但是我们希望promisifySum的签名是promisifySum(a:number,b:number):Promise<[number,number,number]>,所以需要通过buildArgs将promisifySum的参数转换为sum的参数。 当没有提供buildArgs参数时,默认值为:typescript(args:any[],callback:Function)=>{ return [...args,callback] }将
callback放在参数的最后,这是nodejs标准库的异步函数的参数形式。所以当我们没有提供buildArgs参数时,promisify可以直接用来包装nodejs标准库的异步函数。 而当我们要包装非nodejs标准库的异步函数时,需要提供buildArgs参数。parseCallback(results:any[])参数用来指定一个函数将原始函数的回调函数的入参转换为promise的返回结果。比如上例中,sum函数的原始回调是callback(a,b,a+b),但是我们希望promisifySum的返回结果是[a,b,a+b],所以需要通过parseCallback将sum的回调结果转换为promisifySum的结果。当没有提供
parseCallback参数时,默认值为:typescriptconst parseNodejsCallback = (results:any[])=>{ if(results.length===0) return undefined // 因为nodejs标准库的异步函数的回调函数的第一个参数是错误对象 // 当检测到错误时,则抛出错误,将错误作为promise的reject结果 if(results.length>0 && results[0]){ throw results[0] }else{ if(results.length==2) return results[1] return results.slice(1) } }该函数用来处理
nodejs标准库的异步函数的回调结果。错误处理行为: 在
nodejs标准库的异步函数中,如果回调函数的第一个参数不为null,则表示发生了错误,此时promisify会将该错误作为promise的reject结果。 而对于非nodejs标准库的异步函数, 错误并不一定是通过callback传递,也可能是直接throw error。为了处理这种情况,在parseCallback中,当出错时是通过throw error抛出的,promisify会将该错误作为promise的reject结果。