Skip to content

脚本引擎

介绍

脚本引擎分两个版本,js1.0, js2.0,通过系统参数:bingo.script.use.js2.0来进行切换。两个版本脚本引擎差异如下:

语言特性支持

特性项js1.0js2.0说明
ES标准支持情况ES5.1, 部分ES6特性ES2022
模块支持情况commonjses module/commonjs通过系统参数bingo.js2.script.module控制
异步支持(Promise/async/await)NY
setTimeout, clearTimeoutNY
ES6 class supportYY
ProxyYY
SymbolYY
Map, Set, WeakMap, WeakSetYY
Typed ArraysYY
for-ofYY
ReflectYY
Block-scoped declarations (let and const)YY
Optional catch bindingYY
Destructuring assignmentsYY
Default function parametersYY
Spread and rest propertiesYY
Arrow functionsYY
Template literalsYY
Optional chainingYY
** OperatorYY
Nullish Coalescing OperatorYY
generatorsYY
String.prototype.replaceAllYY

js1.0/js2.0均不兼容npm生态。

性能差异

js2.0性能远远优于js1.0, 大部分场景下,性能提升了100%~1000%, 如JSON.parse提升了800%, JSON.stringify提升了500%

js2.0新增加API

因为js2.0支持异步,所以新增加部分异步api:

  • setTimeout
  • clearTimeout
  • db.sql.executeAsync
ts
import * as db from 'db';

function bad() {
    let p = db.sql().executeAsync("select * from m__wasm__cst limit 1", { dynamic: false });
    p.then((value) => {
        console.log(value);
    }).catch((reason) => {
        console.log("execption = ", reason);
    });
}

function ok() {
    let p = db.sql().executeAsync("select * from m__wasm__cst limit 1", { dynamic: true });
    p.then((value) => {
        console.log("affected rows = ", value.AffectedRows);
    }).catch((reason) => {
        console.log("execption = ", reason);
    });
}

console.log("hello 1");
setTimeout(ok, "1000");
console.log("hello 2");
setTimeout(bad, "100");
console.log("hello 3");

输出:

bash
0703 15:27:00.626|debug|vm[1]>>> hello 1 (m__obs:18)
0703 15:27:00.626|debug|vm[1]>>> hello 2 (m__obs:20)
0703 15:27:00.626|debug|vm[1]>>> hello 3 (m__obs:22)
0703 15:27:01.631|debug|vm[1]>>> affected rows =  1 (m__obs:13)
0703 15:27:01.631|debug|vm[1]>>> execption =  Error 
{
    message: "object m__wasm__cst is used but not decorated with @useObject, please decorate it first."
} (m__obs:7)
  • http.client.requestAsync
ts
import * as http from 'http';
import * as context from 'context';

const option: http.ClientOption = {
    baseUrl: context.getHost() + "/u-route/baas/"
}
const headers = {
    "access-token": context.getToken(),
    "content-type": "application/json",
};

const client = http.newClient(option);
let p = client.requestAsync(http.Method.GET, "script/v1.0/declaration", { headers: headers });

p.then((resp) => {
    console.log(`resp length is `, len(resp.body.result));
}).catch((reason) => {
    console.log(`error is `, reason);
});

console.log("hello, here");

输出:

bash
0712 16:46:57.832|debug|vm[68]>>> hello, here (m__httpdemo:19)
0712 16:46:57.832|debug|vm[68]>>> resp length is  2 (m__httpdemo:15)

动态加载模块

commonjs的require函数,esmodule的import函数。

commonjs:

ts
const res = require('./m__util');
res.sayHello('common js dynamic import');

esmodule:

ts
import('./m__util').then((res) => {
    res.sayHello("es module dynamic import");
});

兼容性差异

部分AppCube封装api有些差异:

Decimal类型Exponent方法在某些场景计算结果不同

ts
import * as decimal from 'decimal';

let d1 = decimal.newFromString('-123.4567');
let d2 = decimal.newFromString('-321.231');
let avg = decimal.avg(d1, d2);
console.log("avg :  ", avg);
console.log("avg exponent :  ", avg.Exponent());

js1.0输出结果

bash
617 19:38:03.685|debug|vm[12]>>> avg :   -222.34385 (m__avgdecimal.ts:6:12(36))
0617 19:38:03.685|debug|vm[12]>>> avg exponent :   -16 (m__avgdecimal.ts:7:12(44))

js2.0输出结果:

bash
0617 19:35:29.125|debug|vm[11]>>> avg :   -222.34385 (m__avgdecimal:5)
0617 19:35:29.125|debug|vm[11]>>> avg exponent :   -5 (m__avgdecimal:6)

从输出结果来看,js2.0输出结果更加符合我们的直觉。