网络
虚拟私有云 VPC
弹性公网IP EIP
弹性负载均衡 ELB
NAT网关 NAT
云专线 DC
虚拟专用网络 VPN
云连接 CC
VPC终端节点 VPCEP
企业路由器 ER
企业交换机 ESW
全球加速 GA
企业连接 EC
云原生应用网络 ANC
安全与合规
安全技术与应用
Web应用防火墙 WAF
企业主机安全 HSS
云防火墙 CFW
安全云脑 SecMaster
DDoS防护 AAD
数据加密服务 DEW
数据库安全服务 DBSS
云堡垒机 CBH
数据安全中心 DSC
云证书管理服务 CCM
威胁检测服务 MTD
态势感知 SA
认证测试中心 CTC
边缘安全 EdgeSec
应用中间件
微服务引擎 CSE
分布式消息服务Kafka版
分布式消息服务RabbitMQ版
分布式消息服务RocketMQ版
API网关 APIG
分布式缓存服务 DCS
多活高可用服务 MAS
事件网格 EG
管理与监管
统一身份认证服务 IAM
消息通知服务 SMN
云监控服务 CES
应用运维管理 AOM
应用性能管理 APM
云日志服务 LTS
云审计服务 CTS
标签管理服务 TMS
配置审计 Config
应用身份管理服务 OneAccess
资源访问管理 RAM
组织 Organizations
资源编排服务 RFS
优化顾问 OA
IAM 身份中心
云运维中心 COC
资源治理中心 RGC
解决方案
高性能计算 HPC
SAP
混合云灾备
开天工业工作台 MIW
Haydn解决方案工厂
数字化诊断治理专家服务
云生态
云商店
合作伙伴中心
华为云开发者学堂
华为云慧通差旅
开发与运维
软件开发生产线 CodeArts
需求管理 CodeArts Req
流水线 CodeArts Pipeline
代码检查 CodeArts Check
编译构建 CodeArts Build
部署 CodeArts Deploy
测试计划 CodeArts TestPlan
制品仓库 CodeArts Artifact
移动应用测试 MobileAPPTest
CodeArts IDE Online
开源镜像站 Mirrors
性能测试 CodeArts PerfTest
应用管理与运维平台 ServiceStage
云应用引擎 CAE
开源治理服务 CodeArts Governance
华为云Astro轻应用
CodeArts IDE
Astro工作流 AstroFlow
代码托管 CodeArts Repo
漏洞管理服务 CodeArts Inspector
联接 CodeArtsLink
软件建模 CodeArts Modeling
Astro企业应用 AstroPro
CodeArts盘古助手
华为云Astro大屏应用
计算
弹性云服务器 ECS
Flexus云服务
裸金属服务器 BMS
云手机服务器 CPH
专属主机 DeH
弹性伸缩 AS
镜像服务 IMS
函数工作流 FunctionGraph
云耀云服务器(旧版)
VR云渲游平台 CVR
Huawei Cloud EulerOS
云化数据中心 CloudDC
网络
虚拟私有云 VPC
弹性公网IP EIP
弹性负载均衡 ELB
NAT网关 NAT
云专线 DC
虚拟专用网络 VPN
云连接 CC
VPC终端节点 VPCEP
企业路由器 ER
企业交换机 ESW
全球加速 GA
企业连接 EC
云原生应用网络 ANC
CDN与智能边缘
内容分发网络 CDN
智能边缘云 IEC
智能边缘平台 IEF
CloudPond云服务
安全与合规
安全技术与应用
Web应用防火墙 WAF
企业主机安全 HSS
云防火墙 CFW
安全云脑 SecMaster
DDoS防护 AAD
数据加密服务 DEW
数据库安全服务 DBSS
云堡垒机 CBH
数据安全中心 DSC
云证书管理服务 CCM
威胁检测服务 MTD
态势感知 SA
认证测试中心 CTC
边缘安全 EdgeSec
大数据
MapReduce服务 MRS
数据湖探索 DLI
表格存储服务 CloudTable
可信智能计算服务 TICS
推荐系统 RES
云搜索服务 CSS
数据可视化 DLV
数据接入服务 DIS
数据仓库服务 GaussDB(DWS)
数据治理中心 DataArts Studio
湖仓构建 LakeFormation
智能数据洞察 DataArts Insight
应用中间件
微服务引擎 CSE
分布式消息服务Kafka版
分布式消息服务RabbitMQ版
分布式消息服务RocketMQ版
API网关 APIG
分布式缓存服务 DCS
多活高可用服务 MAS
事件网格 EG
开天aPaaS
应用平台 AppStage
开天企业工作台 MSSE
开天集成工作台 MSSI
API中心 API Hub
云消息服务 KooMessage
交换数据空间 EDS
云地图服务 KooMap
云手机服务 KooPhone
组织成员账号 OrgID
云空间服务 KooDrive
管理与监管
统一身份认证服务 IAM
消息通知服务 SMN
云监控服务 CES
应用运维管理 AOM
应用性能管理 APM
云日志服务 LTS
云审计服务 CTS
标签管理服务 TMS
配置审计 Config
应用身份管理服务 OneAccess
资源访问管理 RAM
组织 Organizations
资源编排服务 RFS
优化顾问 OA
IAM 身份中心
云运维中心 COC
资源治理中心 RGC
区块链
区块链服务 BCS
数字资产链 DAC
华为云区块链引擎服务 HBS
解决方案
高性能计算 HPC
SAP
混合云灾备
开天工业工作台 MIW
Haydn解决方案工厂
数字化诊断治理专家服务
价格
成本优化最佳实践
专属云商业逻辑
云生态
云商店
合作伙伴中心
华为云开发者学堂
华为云慧通差旅
其他
管理控制台
消息中心
产品价格详情
系统权限
客户关联华为云合作伙伴须知
公共问题
宽限期保留期
奖励推广计划
活动
云服务信任体系能力说明
开发与运维
软件开发生产线 CodeArts
需求管理 CodeArts Req
流水线 CodeArts Pipeline
代码检查 CodeArts Check
编译构建 CodeArts Build
部署 CodeArts Deploy
测试计划 CodeArts TestPlan
制品仓库 CodeArts Artifact
移动应用测试 MobileAPPTest
CodeArts IDE Online
开源镜像站 Mirrors
性能测试 CodeArts PerfTest
应用管理与运维平台 ServiceStage
云应用引擎 CAE
开源治理服务 CodeArts Governance
华为云Astro轻应用
CodeArts IDE
Astro工作流 AstroFlow
代码托管 CodeArts Repo
漏洞管理服务 CodeArts Inspector
联接 CodeArtsLink
软件建模 CodeArts Modeling
Astro企业应用 AstroPro
CodeArts盘古助手
华为云Astro大屏应用
存储
对象存储服务 OBS
云硬盘 EVS
云备份 CBR
高性能弹性文件服务 SFS Turbo
弹性文件服务 SFS
存储容灾服务 SDRS
云硬盘备份 VBS
云服务器备份 CSBS
数据快递服务 DES
云存储网关 CSG
专属分布式存储服务 DSS
数据工坊 DWR
地图数据 MapDS
键值存储服务 KVS
容器
云容器引擎 CCE
云容器实例 CCI
容器镜像服务 SWR
云原生服务中心 OSC
应用服务网格 ASM
华为云UCS
数据库
云数据库 RDS
数据复制服务 DRS
文档数据库服务 DDS
分布式数据库中间件 DDM
云数据库 GaussDB
云数据库 GeminiDB
数据管理服务 DAS
数据库和应用迁移 UGO
云数据库 TaurusDB
人工智能
AI开发平台ModelArts
华为HiLens
图引擎服务 GES
图像识别 Image
文字识别 OCR
自然语言处理 NLP
内容审核 Moderation
图像搜索 ImageSearch
医疗智能体 EIHealth
企业级AI应用开发专业套件 ModelArts Pro
人脸识别服务 FRS
对话机器人服务 CBS
语音交互服务 SIS
人证核身服务 IVS
视频智能分析服务 VIAS
城市智能体
自动驾驶云服务 Octopus
盘古大模型 PanguLargeModels
IoT物联网
设备接入 IoTDA
全球SIM联接 GSL
IoT数据分析 IoTA
路网数字化服务 DRIS
IoT边缘 IoTEdge
设备发放 IoTDP
企业应用
域名注册服务 Domains
云解析服务 DNS
企业门户 EWP
ICP备案
商标注册
华为云WeLink
华为云会议 Meeting
隐私保护通话 PrivateNumber
语音通话 VoiceCall
消息&短信 MSGSMS
云管理网络
SD-WAN 云服务
边缘数据中心管理 EDCM
云桌面 Workspace
应用与数据集成平台 ROMA Connect
ROMA资产中心 ROMA Exchange
API全生命周期管理 ROMA API
政企自服务管理 ESM
视频
实时音视频 SparkRTC
视频直播 Live
视频点播 VOD
媒体处理 MPC
视频接入服务 VIS
数字内容生产线 MetaStudio
迁移
主机迁移服务 SMS
对象存储迁移服务 OMS
云数据迁移 CDM
迁移中心 MGC
专属云
专属计算集群 DCC
开发者工具
SDK开发指南
API签名指南
DevStar
华为云命令行工具服务 KooCLI
Huawei Cloud Toolkit
CodeArts API
云化转型
云架构中心
云采用框架
用户服务
账号中心
费用中心
成本中心
资源中心
企业管理
工单管理
客户运营能力
国际站常见问题
支持计划
专业服务
合作伙伴支持计划
我的凭证
华为云公共事业服务云平台
工业软件
工业数字模型驱动引擎
硬件开发工具链平台云服务
工业数据转换引擎云服务

AstroZero脚本开发规则及约束限制

更新时间:2024-12-04 GMT+08:00
分享

脚本性能检查规则

在AstroZero脚本编辑器中编写脚本代码时,请仔细阅读如下内容,了解脚本性能的检查规则。在AstroZero标准页面和高级页面中,对页面性能进行分析时,会分析页面所引用脚本的性能。如果脚本存在性能问题,界面会通过弹框提示您,方便您直观的发现脚本中的问题。如何在标准页面和高级页面进行性能分析,请参见查看AstroZero标准页面性能查看AstroZero高级页面性能

AstroZero低代码平台对脚本进行性能检查遵循的总体原则是:主要检查SELECT语句中,WHERE查询字段是否创建索引,另外对SELECT查询字段和WHERE限制条件进行检查。
  • 静态检查规则
    • 规则1:SELECT语句需要带上where条件

      SELECT语句中缺少查询条件,存在由于查询结果数量过大,导致脚本性能不佳的风险。请确认查询结果,如果查询结果数量过大,建议增加限制条件或采用分页查询,分页查询请见下方推荐代码示例。

      错误代码示例:
      import * as db from 'db';
      let errorDemo = db.sql().exec("select object_name from object_demo order by createddate desc")
      正确代码示例:
      import * as db from 'db';
      let correctDemo = db.sql().exec("select object_name from object_demo where id = ? order by createddate desc")
      推荐代码示例:
      import * as db from 'db';
      let se = db.sql()
      let sqlResult = []
      for(let i=0; i <1000; i++){
          let query_sql = se.exec("select object_name from object_demo limit ${5000*i},5000")
          sqlResult.push(query_sql)
          if(query_sql.length<5000){
              break
          }
      }
    • 规则2:SELECT语句中单次limit查询数量需要低于平台最高查询个数5000的限制

      SELECT语句中单次limit查询数量大于平台限制个数,存在由于查询结果数量过大,导致脚本性能不佳的风险。如果查询结果过大,请判断是否需要增加限制条件或采用分页查询,分页查询请见下方推荐代码示例。

      错误代码示例:
      import * as db from 'db';
      let errorDemo = db.sql().exec("select object_name from object_demo  where object_type = 'Test' limit 100000")
      正确代码示例:
      import * as db from 'db';
      let correctDemo = db.sql().exec("select object_name from object_demo  where object_type = 'Test' limit 3000")
      推荐代码示例:
      import * as db from 'db';
      let se = db.sql()
      let sqlResult = []
      for(let i=0; i <1000; i++){
          let query_sql = se.exec(`select object_name from object_demo limit ${5000*i},5000`)
          sqlResult.push(query_sql)
          if(query_sql.length<5000){
              break
          }
      }
    • 规则3:SELECT语句中谨慎使用区间查询条件

      SELECT语句中使用区间查询(“<>”、“<”、“>”、“>=”、“<=”),存在由于查询结果数量过大,导致脚本性能不佳的风险。如果必须采用区间查询,建议增加limit限制条件,以免影响查询效率。

      错误代码示例:
      import * as db from 'db';
      let errorDemo = db.sql().exec("select object_name from object_demo  where object_num > 50")
      正确代码示例:
      import * as db from 'db';
      let correctDemo = db.sql().exec("select object_name from object_demo  where object_num > 50 limit 3000")
    • 规则4:SELECT语句中查询字段不在表的索引库中

      如果SELECT语句where条件中,查询字段并未创建索引,请判断该字段是否需要创建索引,以提高代码查询效率。

      错误代码示例:
      import * as db from 'db';
      let errorDemo = db.sql().exec("select object_name from object_demo  where object_id = ?")

      表“object_demo”中的“object_id”并没有创建索引。

      正确代码示例:
      import * as db from 'db';
      let correctDemo = db.sql().exec("select object_name from object_demo where id = ?")

      表“object_demo”中的“id”创建了索引。

    • 规则5:SELECT语句中尽量避免同时从大于等于4张表中取数据

      SELECT语句中,进行多表关联查询时,尽量不要同时从大于或等于4张表中获取数据。如果必须要查询大于或等于4张表的数据时,建议先通过关联少于4张表进行查询,然后根据查询结果再做关联查询,保证每次关联查询的表数量少于4,以提高查询效率。

      错误代码示例:
      import * as db from 'db';
      let errorDemo = db.sql().exec("select a.item as item1, b.item as item2, c.item as item3 ,d.item as item4, e.item as itmem5 from object_demo1 as a object_demo2 as b, object_demo3 as c ,object_demo4 as d, object_demo5 as e where a.id=b.objectid and b.name = c.objectid and c.name = d.objectid and d.name = e.objectid and e.name ='Test'")
      正确代码示例:
      import * as db from 'db';
      let sqlResult1 = db.sql().exec("select c.item as item3, d.item as item4, e.item as itmem5 from object_demo3 as c ,object_demo4 as d, object_demo5 as e where c.name = d.objectid and d.name = e.objectid and e.name ='Test'")
      let sqlResult = []
      let item3s = "'"+sqlResult1.map(item=>{item.item3}).join("','")+"'"
      let sqlResult2 = db.sql().exec('select a.item as item1, b.item as item2, c.item as item3 from object_demo1 as a object_demo2 as b, object_demo3 as c where a.id=b.objectid and b.name = c.objectid and c.item in ('+item3s+')')
      for(let i in sqlResult1){
       for(let j in sqlResult2){
        if i.item3 == j.item3:
         sqlResult.append({
          "item1":j.item1,
          "item2":j.item2,
          "item3":i.item3,
          "item4":i.item4,
          "item5":i.item5
         })
       }
      }
    • 规则6:SELECT语句中聚集函数必须增加别名

      SELECT语句中,聚合函数必须使用别名方式存储查询结果,以免因聚合函数返回的结果不一致,导致存在兼容性问题。

      错误代码示例:
      import * as db from 'db';
      let errorDemo = db.sql().exec("select count(*) from object_demo where object_name = 'Test'")
      正确代码示例:
      import * as db from 'db';
      let correctDemo = db.sql().exec("select count(*) as count from object_demo where object_name = 'Test'")
      推荐代码示例:
      ***聚合函数示例 ****
      select count(*) as count_res,
      select max(*) as max_res,
      select min(*) as min_res,
      select avg(*) as avg_res,
      select sum(*) as sum_res  
    • 规则7:SELECT语句中严禁使用“select from...”形式查询语句

      严禁使用“select ...”形式查询语句,请指出select的具体字段。

      错误代码示例:
      import * as db from 'db';
      let errorDemo = db.sql().exec("select from object_demo where object_name = 'test'")
      正确代码示例:
      import * as db from 'db';
      let correctDemo = db.sql().exec("select id, object_type from object_demo where object_name = 'test'")    
    • 规则8:SELECT语句中拼接的参数值请谨慎使用入参变量

      SELECT语句中,拼接的参数值请谨慎使用入参变量,以免引起SQL注入的风险。

      错误代码示例:
      import * as db from 'db';
      let errorDemo = "select id,name from object_demo where id = ";
      errorDemo += input.parameter 
      let errorDemoResult = db.sql().exec(errorDemo)

      其中,“input.parameter”为脚本入参。

      正确代码示例:
      import * as db from 'db';
      let correctDemo = "select id,name from object_demo where id = ?";
      let correctDemoResult = db.sql().exec(correctDemo, { params: [input.parameter] })

      其中,“input.parameter”为脚本入参。

    • 规则9:“for”循环中请谨慎使用SELECT语句

      “for”循环中,请谨慎使用SELECT语句,以免后续进行结果赋值时,由于数据过多,导致内存溢出。

      错误代码示例:
      import * as db from 'db';
      for (let i = 0; i < input.para.length; i++) {
        db.sql().exec("select id,name from object_demo where id = Test'");
      }
      正确代码示例:
      import * as db from 'db';
      db.sql().exec("select id,name from object_demo where id = 'Test'");
    • 规则10:SELECT语句中谨慎使用order by

      SELECT语句中,请谨慎使用order by。如果需要使用order by,请为排序字段增加索引,以提高查询效率。如果无法增加索引,需要关注是否存在查询性能低下的风险。

      错误代码示例:
      import * as db from 'db';
      let errorDemo = db.sql().exec("select object_name from object_demo  where object_id = 'Test' Orde by createdDate") 

      表“object_demo”中的“createdDate”,并没有创建索引。

      正确代码示例:
      import * as db from 'db';
      let correctDemo = db.sql().exec("select object_name from object_demo where id = 'Test' Order by createdDate")

      “object_demo”中的“createdDate”,创建了索引。

  • 动态检查规则

    脚本运行时,触发动态检查。动态检查规则以静态检查规则为基础,无法检查SQL注入以及for循环中的SQL项。

    • 当存在脚本性能问题时,通过弹框界面提示给用户,方便用户直观发现脚本中的问题。
    • 当不存在性能问题时,便不展示弹框页面,以免影响用户开发。

脚本开发规范及限制

在AstroZero脚本编辑器中编写脚本代码时,建议您先了解脚本编写的规范和限制,便于快速地完成脚本代码的编写。

  • 命名限制

    所有的名称定义要能体现其作用,避免使用缩写(专有名词除外)。

    • 脚本采用小驼峰命名,例如createDeviceInstance。
    • 结构体(struct)采用大驼峰命名,例如QueryPaymentResult。
    • 结构体内的字段采用小驼峰命名,例如customerName 。
    • 类、枚举值和接口采用大驼峰命名。
      class Comments {...}
      interface Console {...}
      enum Direction { Up = 1, Down, Left, Right}
    • 函数采用小驼峰命名。
      addOfferingAssociatePriceAndStock(input: Input): Output {...}
    • 属性或变量采用小驼峰命名。
      class Comments {
                 userId: String;
                 content: String;
             }
      let oneComments = newComments();

      变量为单数时,命名包含对象名称,如level1Catalog、level2Catalog。变量为复数时,命名包含集合名称,如attributeRelationRuleList。

  • 脚本定义规则
    • 每个字段的定义,均需要定义type、label、description、required和isCollection,有默认值的非必填。
    • 当字段为集合类型时,需要定义成“[]”
      @action.param({
          type: "Attribute",
          label: "Attribute",
          description: "attributeList",
          required:false
          isCollection: true
      })
      attributeList: Attribute[];
    • @action.object时,需要在脚本中详细定义清楚Object,不要引用其他脚本的Object。
    • 如果是嵌套结构体,则从下到上粒度依次变小。
      export class ProductObject {
             //ignore
      }
      
      export class StockObject {
             //ignore
      }
      
      export class ProductStock {
          @action.param({ type: 'Struct', label: "ProductObject", isCollection: false })
          productInfomation: ProductObject;
      
          @action.param({ type: 'Struct', label: "StockObject", isCollection: false })
          stock: StockObject;
      }
      
      @action.object({ type: "param" })
      export class Input {
          @action.param({ type: 'String', label: "productId", isCollection: false })
          productId: String;
      }
    • 不需要定义多个Output对象,可以直接在方法使用定义的对象出参。

      【推荐】:

      @action.object({ type: "param" })
      export class Input {
          @action.param({ type: 'String', label: "productId", isCollection: false })
          productId: String;
      }
      
      @action.object({ type: "param" })
      export class getProductStock {
      @action.method({ input: "Input", output: "ProductStock", label: 'getProductStock' })
      getProductStock(input: Input): ProductStock {

      【不推荐】:如果出参对象包含从外部引入的对象,还是要按该方式定义。

      @action.object({ type: "param" })
      export class Input {
          @action.param({ type: 'String', label: "productId", isCollection: false })
          productId: String;
      }
      
      @action.object({ type: "param" })
      export class Output {
          @action.param({ type: 'Object', isCollection: false })
          ProductStock: ProductStock;
      }
      
      @action.object({ type: "param" })
      export class getProductStock {
      @action.method({ input: "Input", output: "Output", label: 'getProductStock' })
      getProductStock(input: Input): Output {
    • 除非业务有特殊要求,新增修改脚本不返回结果码和结果信息。
  • 脚本注释的原则和写法
    无用的代码不能以注释形式存在,能用代码说明的尽量不要添加注释,脚本注释尽可能简洁。建议注释统一用英文,出入参不必写注释说明。
    • 在函数方法和结构体的元数据描述上,添加注释。
      /**
      * 根据产品ID查询产品详情信息
      */
      @action.method({ input: "Input", output: "Output", label: 'queryProductDetailForCart' })
    • 方法内关键业务语句前,必须添加注释。
      • 方法内的单行注释以“//”开头,应放在相关代码的上方或右方,不可放于下方。如果放于上方,注释需与前面的代码间用空行隔开。
      • 注释与代码的比例没有量化标准。在删掉所有的代码内容、仅保留代码层级结构和注释,如果通过注释,可以很容易理解方法内都做了哪些事情(类似于伪代码),则认为注释比例合理。
      // 校验密码是否正确
      let password = input.password;
      if (accountRecord["Password"] != password) {
      error.name = "CM-001003";
      error.message = "Invalid loginId or password.";
      throw error;
      }
  • 脚本间相互引用规则
    • 脚本中不要包含没用到的标准库或对象的引用。
      例如,如果实际没用到sys模块的任何方法,则不要包含如下语句:
      import * as sys from 'sys';

      如果实际上只用到了CA_PC_Offering对象,则示例语句中其他对象需要删除:

      @useObject(['CA_PC_FeeItemDef', 'CA_PC_Offering', 'CA_PC_CatalogOffering', 'CA_PC_Catalog', 'CA_PC_OfferingAttribute'])
    • 只引用使用到的对象,而不用import *。

      【推荐】:

      import { OfferingObjectQuery } from './ca_pc__getOfferingObject';
      import { setI18nError } from 'context';
      import { sql } from 'db';

      【不推荐】:

      import * as queryOfferingObjectAction from './ca_pc__getOfferingObject';
      import * as context from 'context';
      import * as db from 'db';
    • @action.method属于必须的方法注解,写在方法上面。
      @action.method({ input: "Input", output: "Output", label: 'queryClassification' })
      queryClassification(input: Input): Output {
      ...
      }
    • 为方便页面直接调用脚本,仅在脚本最后统一导出需要的对象,而不是导出所有对象。如果不需要,可以不用导出。

      例如,getOfferingObject脚本中最后一行导出OfferingObjectQuery对象:

      export let theAction = new OfferingObjectQuery();
    • 可以把公共的对象Object定义,按分类放在一些公共的脚本里(例如pc_XXX.ts、cm_XXX.ts),其他需要的脚本直接引用即可。
  • 语法规则
    • 对象判空

      单个对象示例:

      if(object){
          //ignore
      }

      集合对象示例:

      if(collection&&collection.length!=0){
          //ignore
      }
    • 数字类型统一定义成“Number”、日期类型定义成“Date”
      @action.param({
          type: "Date",
          label: "effectiveTime",
          description: "Date."
      })
      effectiveTime: Date;
      
      @action.param({
          type: "Number",
          label: "salePrice",
          description: "salePrice."
      })
      salePrice: number;
    • 变量或数组定义时,要说明类型,集合需要加上泛型。
      let isDone:Boolean = false;
      let decLiteral : number =6;
      let productList = new Array<productObject>();
    • 遍历循环推荐用“forEach”,不推荐用“for…in”
      testArray.forEach((value, index, array )=>{
             //ignore
      });
    • 推荐用“let”变量声明,不推荐用“var”

      【推荐】:

      let offeringId : String = “aaa”;

      【不推荐】:

      var offeringId = “aaa”;
    • 代码有对象声明时,推荐使用“.fieldName”获取对象的字段,而不是用“[‘fieldName’]”

      【推荐】:

      offeringStruct.id = result[i].base.offeringId;

      【不推荐】:

      offeringStruct.id = result[i][‘base’][‘offeringId’];
    • 在需要默认值的情况下,使用“||”代替“if”判断。
      function(value){
             //使用||对value进行判空
             value = value || “hello”
      }
    • 创建一个已知对象时,推荐用“new”方法。

      【推荐】:

      let offeringIdRequest = new OfferingIdRequest();
      offeringIdRequest.catalogList = catalogList;
      offeringIdRequest.classificationList:=classificationList;
      let getOfferingIdByConditionInput = {
             "OfferingIdRequest": offeringIdRequest
      }

      【不推荐】:

      let getOfferingIdByConditionInput = {
             "OfferingIdRequest": {
                    "catalogList": catalogList,
                    "classificationList": classificationList,
                    "status": "",
                    "stockCondition": "",
                    "keyWord": "",
                    "offset": "",
                    "limit": ""
             }
      }
    • 函数定义
      let traitRec = function(xxxx,xxx) {
          //ignore
       }

      只能在函数定义后的语句中,使用该函数。

    • 没有初始化值的变量申明,使用“undefined”,不要使用“null”
      let object = undefined;
    • 局部变量需要在“class”内定义,不要在全局命名空间内定义类型/值(即不要在“class”外定义变量),常量可以定义成全局。
      let identityIdList = [];
    • 使用“lambda”表达式代替匿名函数。

      只有需要时,才把“arrow”函数的参数括起来。正确使用“arrow”的示例如下:

      x => x + x
      (x,y) => x + y
      <T>(x: T, y: T) => x === y
  • 脚本SQL语句规则
    • 不推荐用拼接SQL方法,避免注入风险。
      let sql = "select id,name,ExternalCode,FeeType,FeeItemName,FeeItemDescription,Remark,Status from CA_PC_FeeItemDef where 1=1";
      if (!InputParams.id && !InputParams.name && !InputParams.feeType && !InputParams.feeItemName && !InputParams.status) {
             context.setI18nError("ca_pc__001013");
             return;
      }
      if (InputParams.id) {
             sql += "and id ='" + InputParams.id + "'"
      }
    • 多表复杂查询建议用“sql.exec()”“sql.excute()”方法,“excute()”方法比“exec()”多返回字段集和操作成功数。
      let result = execsql.exec("select id,name,OfferingId,ParentId,SkuCode,ChannelId,Status,ProductLabel,PriceCode,DefaultChoose,PaymentType from CA_PC_Product where id in (" + str + ")",
      {
             params: productId
      });

      多表复杂查询只能使用拼接SQL方法,但是有限制,例如示例中的“str”要求如下:

      • str如果来源于入参,则入参在拼接SQL之前需要进行校验,以免引入SQL注入攻击。如果来源于内部数据,可以不进行校验。
      • 不推荐直接在SQL中拼接入参,应该采用在SQL中拼接占位符,然后把入参放入参数的数组中,例如:
        attriSql = "select AttrDef from DE_DeviceDefAttri where DeviceDef=? and ExternalCode=? and AttrType='DYNAMIC' and ValueType='1'";
        attriRecords = db.sql().exec(attriSql, {
        		params: [deviceDefId, defExternalCode]
        	});
    • 对于单表查询和增删改SQL,推荐使用Orm接口方法。

      Options选项可以选择返回字段、排序、聚合运算和分页等功能。当value不存在时,默认为null类型。

      let CA_PC_Stock = db.object('CA_PC_Stock');
      let amountCount = 0;
      if (UpdateStock.amount) {
             let record = { Amount: UpdateStock.amount };
             amountCount = CA_PC_Stock.updateByCondition({
                    "conjunction": "AND",
                    "conditions": [{
                           "field": "SkuCode",
                           "operator": "eq",
                           "value": UpdateStock.skuCode
                    }]
             }, record);
      }
    • 避免在循环中调用方法和操作数据库,可以用“in”来查询在集合中的结果。
      let productIdList = input.productId;
      let str = "";
      let arr = [];
      for (let i = 0; i < productIdList.length; i++) {
             arr[i] = "?";
      }
      str = arr.toString();
      let result = execsql.exec("select id,name,OfferingId,ParentId,SkuCode,ChannelId,Status,ProductLabel,PriceCode,DefaultChoose,PaymentType from CA_PC_Product where id in (" + str + ")",
      {
             params: productIdList
      });
    • 对sql进行优化时,尽量使用有索引的字段,避免使用没有索引的字段。
    • 批量操作数据库时,尽量使用已封装好的批量操作接口。

      例如,Orm.batchInsert、Orm.batchUpdate接口和Orm.deleteByCondition批量删除接口。如果批量创建父子对象记录,且批量创建的记录在一个完整的事务中,全部成功或全部失败,建议使用Orm.compositeInsert接口。

      var s = db.object('Customer__CST');
      var records = [];
      var record = {
          "name": "hello",
          "count__CST": 123,
          "Contacts": {
              "records": [
                  {
                      "name": "hello_contact1"
                  },
                  {
                      "name": "hello_contact2"
                  },
              ]
          }
      };
      records.push(record);
      var ids = s.compositeInsert(records);
      console.log("id list = ", ids);
      
      count = s.count();
      console.log("record count = ", count);
    • 匹配查询推荐用like,日期比较推荐用“<”“>”

      【推荐】:

      select id from t where name like ‘abc%’
      select id from t where createdate>=’2005-11-30’ and createdate<’2005-12-1’

      【不推荐】:

      select id from t where substring(name,1,3)=’abc’
      select id from t where datediff(day,createdate, ‘2005-11-30’)
    • 使用exists替代in,使用not exists替代not in。

      【推荐】:

      SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND EXISTS (SELECT ‘X’FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB’)

      【不推荐】:

      SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC =’MELB’)
    • 避免在索引列上使用is null和is not null,会造成索引失效。

      【推荐】:

      SELECT … FROM DEPARTMENT WHERE DEPT_CODE >=0

      【不推荐】:

      SELECT … FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL
    • 注意事项
      • 尽量避免Select子句中,使用“*”。
      • 尽量避免在where子句中,使用!=或<>操作符。
      • 尽量避免在where子句中,对字段进行函数操作。
      • 尽量避免在SQL中,使用 “!=” 、“||”、“+”符号。
      • 尽量避免在where条件中,做数据筛选。
      • 尽量避免查询中,按字段排序。
      • 尽量避免多表关联查询和嵌套查询,不要使用超过2表的关联查询。
      • 不要在循环内重复使用同一条件查询,应该在循环外处理。例如,公共数据仅在循环外查询一次。
      • 不要在同一个脚本的多个方法内,使用同一条件多次查询,可以定义类的成员变量。
      • 避免关联查询

        关联的条件很多情况下都是唯一的,可以提前做单独查询。例如,使用公共数据作为后续条件,避免关联查询。

      • 避免频繁的数据库交互

        例如,查询5000条数据,查询补充数据的时候,不要在循环内多次交互数据库,把可以合并的条件在循环外拼接并进行一次性查询,在循环内只需要从结果集中获取数据,可以极大提升查询性能。

      • 尽量利用对象做临时缓存

        例如查询到DeviceDef后,按照“id:Object”的方式存起来,后续查询时先判断缓存对象中是否已经存在,如果存在则直接获取不再查询。

  • 脚本代码风格限制
    • 每句话后面加分号,脚本写完右键选择“Format Document”统一格式。
    • string类型赋值统一使用双引号,获取字段统一使用单引号。
    • 相关代码写在一起,不相关逻辑最好以空行隔开。
    • 总是使用“{}”把循环体和条件语句括起来。
    • 开始的“{”总是在同一行。
    • 小括号里开始不要有空白逗号,冒号、分号后要有一个空格。
      for (var i = 0, n = str.length; i < 10; i++) { }
      if (x < 10) { }
      function f(x: number, y: string): void { }
    • 每个变量声明语句只声明一个变量。

      例如,使用如下方式

      var x = 1; var y = 2; 

      而不是下面的方式

      var x = 1, y = 2;
    • else要在结束的“}”后,另起一行。
    • 一个函数仅完成一件功能,即使是简单功能也应该编写单独的方法实现。
    • 单个方法的方法体不要太长,建议控制在150行以内,保证代码可读性,也方便维护、测试。
  • 脚本扩展名限制

    因为脚本实际上是存在数据库中的,所以脚本没有路径的概念,扩展名也没有特别的意义。

    导入模块时,尽量采用不带扩展的方式。如果必须要带扩展名,只允许“.ts”扩展名文件。

    import * as circle from './circle';
  • 脚本循环依赖限制

    当循环调用模块时,一个模块可能在未完成执行时被返回。因此,需要仔细地规划模块间调用,以允许循环模块依赖在应用程序内正常工作。

    例如,脚本a:

    console.log('a 开始');
    exports.done = false;
    import * as b from 'b';
    console.log('在 a 中,b.done = ', b.done);
    exports.done = true;
    console.log('a 结束');

    脚本b:

    console.log('b 开始');
    exports.done = false;
    import * as a from 'a';
    console.log('在 b 中,a.done = ', a.done);
    exports.done = true;
    console.log('b 结束');

    脚本main:

    console.log('main 开始');
    import * as a from 'a';
    import * as b from 'b';
    console.log('在 main 中,a.done = ', a.done ',b.done = ', b.done);

    当main加载a时,a又加载b。 此时,b又会尝试去加载a。 为了防止无限的循环,会返回一个a的exports对象的未完成的副本给b模块。然后b完成加载,并将exports对象提供给a模块。当main加载这两个模块时,都已完成加载,因此该程序的输出会是:

    main 开始
    a 开始
    b 开始
    在 b 中,a.done = false
    b 结束
    在 a 中,b.done = true
    a 结束
    在 main 中,a.done=true,b.done=true
提示

您即将访问非华为云网站,请注意账号财产安全

文档反馈

文档反馈

意见反馈

0/500

标记内容

同时提交标记内容