Skip to content

Script Engine ​

Introduction ​

The script engine has two versions: js1.0 and js2.0. The script engine can be switched through the system parameter bingo.script.use.js2.0 . The differences between the script engines of the two versions are as follows:

Language feature support ​

Featurejs1.0js2.0Description
Support for ES standardsES5.1, partial support for ES6+ES2022
Module supportcommonjses module/commonjsswitch module mode by bingo.js2.script.module system parameter.
Asynchronous Support (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

both js1.0 and js2.0 are not compatible with the'npm' ecosystem.

Performance Differences ​

The performance of js2.0 is much better than that of js1.0. In most scenarios, the performance is improved by 100% to 1000%. For example, JSON.parse is improved by 800%, and JSON.stringify is improved by 500%.

New APIs in JS 2.0 ​

Because js2.0 supports asynchronization, some asynchronization api are added:

  • 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");
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");

output:

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)
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");
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");

output:

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)
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)

dynamicly import module ​

commonjs uses the require function, and esmoudle uses the import function.

commonjs:

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

esmodule:

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

Compatibility Differences ​

Some AppCube APIs are different:

The Exponent method of the Decimal type has different results in some scenarios. ​

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());
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 Output Result

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))
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))

The output of js2.0 is as follows:

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)
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)

From the output, the js2.0 output is more in line with our intuition.