App Engine 之 Action 中的装饰器

举报
云在天 发表于 2020/05/15 17:18:39 2020/05/15
【摘要】 本文探索了App Engine 脚本里的param/method/useObject等装饰器的原理,帮助用户理解脚本代码。

Action是指可以在Flow, Process, Business Process等对象中调用的Script

Action需要满足如下条件:

  • 有明确的输入输出参数

  • 有唯一的入口方法

下面是一个是一个计算器Action的示例代码:

 

/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2012-2019. All rights reserved.
 *
 * The more action information please see:
 * https://dev.besclouds.com/u-route/baas/doc/blog/#/zh-cn/script/action
 *
 */
 
import { Decimal } from 'decimal';
import { Error } from 'error';
 
export class Input {
    @action.param({ type: "String", required: true, description: "the operation type" })
    op: string;
 
    @action.param({ type: "Number", required: true, description: "the operation value 1" })
    value1: Decimal;
 
    @action.param({ type: "Number", required: true, description: "the operation value 2" })
    value2: Decimal;
}
 
export class Output {
    @action.param({ type: "Number", required: true })
    result: Decimal;
}
 
export class Calculator {
    @action.method({ input: "Input", output: "Output", description: "do a operation" })
    run(input: Input): Output {
        let output = new Output();
        switch (input.op) {
            case "+":
                output.result = this.sum(input.value1, input.value2);
                break;
            case "-":
                output.result = this.sub(input.value1, input.value2);
                break;
            default:
                throw new Error("00001", `unsupported calculator operator ${input.op}`);
        }
 
        return output;
    }
 
    sum(a: Decimal, b: Decimal): Decimal {
        return a.Add(b)
    }
 
    sub(a: Decimal, b: Decimal): Decimal {
        return a.Sub(b)
    }
}

Action可以通过restful请求调用,发送如下请求参数进行求和计算:

 

{
    "op": "+",
    "value1": 99,
    "value2": 100
}

  

看到这里,小伙伴可能对上面的代码中的几个装饰器有些疑问。(装饰器是Typescript为类声明及类成员添加标注的一种方式,了解更多可以到这里:https://www.w3cschool.cn/typescript/typescript-decorators.html )

 

从App Engine官方文档来看,代码中几个装饰器的具体作用如下:

@action.param:注解参数。所有的输入或输入参数必须封装在一个class中,作为实例成员,每一个参数均被action.param注解。

@action.method:标识Action的入口方法。被标识的方法必须是class的实例方法,且在一个Action文件中,有且只能有一个入口方法。

 

看到这里,连小编也是一头雾水,什么是入口方法?为什么加个method 装饰器就能标识一个入口方法?为什么要用param 装饰器注解参数呢?啥叫注解?这是什么原理呢?于是小编就寻找这些装饰器的定义,看看它们到底是怎么实现的。

结果发现,这些装饰器函数只有空空的声明,根本没有实现代码,它们看起来不执行任何动作:

interface Action {
    /**
     * To mark the class as an action parameter class or method class.
     * @returns {Function|*}
     */
    object(options: ObjectOptions): Function;
    /**
     * To mark the entry point method of the action
     * @returns {Function|*}
     */
    method(options: MethodOptions): Function;
    /**
     * To mark action's parameter option
     * @returns {Function|*}
     */
    param(options: ParamOptions): Function;
}

 

Typescript本身是不会定义入口方法的。所谓的入口方法即类似于C语言的main()函数,Typescript 没有main()函数,它是按代码行自上至下的顺序依次执行的。我们可以看到,上面的Action 代码只定义了类,并没有在代码中实例化类,所以把上面的代码用标准的Typescript编译器编译运行后,不会执行任何动作。

 

那么这里的method装饰器是怎样把run()函数定义为该Action的入口方法呢?在咨询了我们的开发大牛老邓同学之后,小编总算明白了,原来App Engine的编译器做了手脚。

App Engine 在编译上述代码时,通过分析语法树,将  @action.method 装饰的方法所在的类实例化,并在运行时通过实例调用了被装饰的run()方法,原来这一切动作都在我们看不见的地方发生了!

 

那么@action.param 所谓的注解是什么作用呢?我们来看一下这段代码:

    @action.param({ type: "String", required: true, description: "the operation type" })
    op: string;

代码通过Action.param 告诉编译器,被装饰的成员是一个String类型,且作为入参,必须携带该参数。AppEngine在运行代码时,如果发现该入参成员为空,或者该入参成员不是String类型,那么会报错。反之,如果这里不加@action.param装饰,那么AppEngine运行时就不会强制检查入参空值及类型。

这下你明白了吗?

 

再来看另外一个我们会经常遇到的装饰器:

@useObject(['foo'])

在脚本中,引用对象前总能看到useObject装饰器。这个装饰器的作用是告诉编译器,这段代码引用了一个叫作 foo 的对象,打包编译时需要将 foo 打包进来不要丢了。小编咨询了老邓,这个装饰器已经是历史遗留了,很早之前的版本没有APP的概念,对象与代码没有像当前版本那样都关联在APP下,所以就要通过 useObject 装饰器告诉编译器需要打包哪些对象。为了保持兼容性,当前版本仍保留了useObject 装饰器。你可能会发现,当前版本在有些情况下编译器仍会提示使用对象前请先使用useObject”,所以在脚本中引用对象前,小编还是建议用useObject 装饰器。在未来版本,该装饰器可能会真正退出历史舞台。



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。