【问题标题】:Typescript, decorate async function打字稿,装饰异步功能
【发布时间】:2018-05-10 18:53:02
【问题描述】:

我正在尝试用一些异步函数#2 来装饰异步函数#1。

例如

function func2(param) {
   return (target: any, propertyKey: string, descriptor: PropertyDescriptor) =>    {
   //make async operations and then return descriptor
}


@func2(param)
async function func1() {
    await .... //some async operation
    await .... //some async operation
}

所以,主要思想是在装饰器中执行一些异步操作,然后在主函数中执行其他异步调用。

是否可以使用 typescript 装饰器来制作这个?

提前谢谢你。

【问题讨论】:

    标签: typescript ecmascript-6 async-await decorator


    【解决方案1】:

    装饰器只能用于类方法而不是常规函数,因此这是一个限制,但如果将函数放在类中,则可以轻松替换原始函数并执行其他异步任务:

    function func2(param: number) {
        return (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<(... params: any[])=> Promise<any>>) => {
            let oldFunc = descriptor.value;
            descriptor.value = async function (){
                var result = await oldFunc.apply(this, arguments);
                await delay(param) //some async operation
                console.log("delay 3");
                return result;
            }
        }
    }
    
    class Test {
        @func2(1000)
        async func1(timout: number) {
            await delay(timout) //some async operation
            console.log("delay 1");
            await delay(timout) //some async operation
            console.log("delay 2");
        }
    }
    
    new Test().func1(1000);
    // Util function 
    async function delay(timeout: number) {
        return new Promise<void>((resolve) => setTimeout(() => {
            resolve();
        }, timeout));
    }
    

    【讨论】:

    • 我见过的最优雅的解决方案。
    • 不错的解决方案!有没有办法定义一个既适用于异步方法又适用于非异步方法的装饰器,还是我必须定义两个?我正在编写一个装饰器来测量执行一个方法需要多长时间。
    • @the21st 我认为在这种情况下,您实际上不需要将装饰器限制在任何东西上。只需测试函数的返回是否有 then 并调用它来链接您想要为 promise 版本执行的任何其他操作。 (你不能使用异步,因为那意味着被装饰的函数总是会返回一个你不想要的承诺)
    【解决方案2】:

    如果有人偶然发现我遇到的同样问题,并希望使用异步函数装饰器(在我的情况下从 DB 访问令牌对象)检索一些值并将其传递给您可以使用这些方法的方法。

    您只需要推送到参数数组。

    装饰函数

    export const authorizeXero = () => {
        return (target: any, propertyKey: string, descriptor: any) => { 
            const fn = descriptor.value;
            descriptor.value = async function (...args: any[]) { // anything that was passed in the arguments in instance method (it can be empty)
                let tokens = await fetchSavedXeroTokens()
                tokens = await checkIfXeroTokensStillValid({...tokens})
                tokens = await refreshXeroTokens({...tokens})
                tokens = await saveXeroRefreshToken({...tokens})
                const {access_token,refresh_token} = tokens
                args.push(access_token) // pushes value to the array that will be available to decorated methods
                return fn.apply(this, args);
            }    
        }
    } 
    

    实例方法示例

    @authorizeXero()
    async getLatestInvoices (...params:any) {
        const accessToken = params[0] // everything that is stored in args under decorator function
        const allInvoices = await this.fetchInvoices({accessToken,maxPages:30})
        const xe = allInvoices.map((invoice:any)=>{
            return {'invName':invoice.InvoiceNumber,'orderName':invoice.Reference}
        })
        return xe
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-28
      • 1970-01-01
      • 2018-11-07
      • 2020-01-31
      • 2021-10-19
      • 2016-09-27
      • 2018-06-21
      • 2019-07-29
      相关资源
      最近更新 更多