使用JSVM-API接口进行任务队列相关开发
======================

#### 简介

在虚拟机内启动任务队列，检查队列中是否有待处理的微任务。任务队列可由外部事件循环执行。

#### 基本概念

*   **任务队列**：用于管理异步任务的调度和执行，确保任务按顺序处理。
*   **微任务**：微任务是一种任务调度机制，主要用于处理那些需要尽快执行的较小任务，它们通常具有较高的优先级。

#### 接口说明

| 接口 | 功能说明 |
| :-- | :-- |
| OH\_JSVM\_PumpMessageLoop | 启动任务队列的运行 |
| OH\_JSVM\_PerformMicrotaskCheckpoint | 执行任务队列里的微任务 |
| OH\_JSVM\_SetMicrotaskPolicy | 设置微任务执行策略 |

#### 使用示例

JSVM-API接口开发流程参考[使用JSVM-API实现JS与C/C++语言交互开发流程](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/use-jsvm-process)，本文仅展示接口对应的C++相关代码。

权限要求：Wasm字节码需要应用拥有JIT权限才能执行，可参考[JSVM 申请JIT权限指导](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/jsvm-apply-jit-profile)申请对应权限。

运行限制：当前 JSVM 版本在坚盾守护模式下将禁用 WebAssembly 全部功能模块。开发者需针对此限制进行应用兼容性评估，具体技术规范详见[JSVM 坚盾守护模式](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/jsvm-secure-shield-mode)。

#### \[h2\]OH\_JSVM\_PumpMessageLoop & OH\_JSVM\_PerformMicrotaskCheckpoint

启动任务队列，执行任务。

cpp部分代码：

#include <chrono>
#include <cstring>
// ...

// 待执行的js代码
static const char \*STR\_TASK = R"JS(
    // wasm 字节码 (以add 模块为例)
    // 以下 wasmBuffer 对应的 wasm 字节码文本格式如下所示，只包含了一个函数 add
    // (module
    //   (func $add (param $lhs i32) (param $rhs i32) (result i32)
    //     local.get $lhs
    //     local.get $rhs
    //     i32.add
    //   )
    //   (export "add" (func $add))
    // )
    var wasmBytes = new Uint8Array(\[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01,
                                       0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07,
                                       0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01,
                                       0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b\]);

    var p = WebAssembly.instantiate(wasmBytes, {});
    p.then((result) => {
        consoleinfo("Called with instance " + result);
    });
    p.finally(() => {
       consoleinfo("Called Finally");
    });
)JS";

// 保证js代码中的打印信息可以正常输出
static JSVM\_Value ConsoleInfo(JSVM\_Env env, JSVM\_CallbackInfo info)
{
    size\_t argc = 1;
    JSVM\_Value args\[1\];
    #define MAX\_LOG\_LENGTH 255
    char log\[MAX\_LOG\_LENGTH + 1\] = "";
    size\_t logLength = 0;
    JSVM\_CALL(OH\_JSVM\_GetCbInfo(env, info, &argc, args, NULL, NULL));

    OH\_JSVM\_GetValueStringUtf8(env, args\[0\], log, MAX\_LOG\_LENGTH, &logLength);
    log\[MAX\_LOG\_LENGTH\] = 0;
    OH\_LOG\_INFO(LOG\_APP, "JSVM API TEST: %{public}s", log);
    return nullptr;
}

// 注册consoleinfo的方法
JSVM\_CallbackStruct param\[\] = {
    {.data = nullptr, .callback = ConsoleInfo},
};
JSVM\_PropertyDescriptor descriptor\[\] = {
    {"consoleinfo", NULL, &param\[0\], NULL, NULL, NULL, JSVM\_DEFAULT},
};

static int32\_t TestJSVM()
{
    JSVM\_InitOptions init\_options;
    memset(&init\_options, 0, sizeof(init\_options));
    if (g\_aa == 0) {
        OH\_JSVM\_Init(&init\_options);
        g\_aa++;
    }
    // 创建JavaScript虚拟机实例,打开虚拟机作用域
    JSVM\_VM vm;
    JSVM\_CreateVMOptions options;
    memset(&options, 0, sizeof(options));
    CHECK(OH\_JSVM\_CreateVM(&options, &vm));
    JSVM\_VMScope vm\_scope;
    CHECK(OH\_JSVM\_OpenVMScope(vm, &vm\_scope));

    JSVM\_Env env;
    CHECK(OH\_JSVM\_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor\[0\]), descriptor, &env));
    JSVM\_EnvScope envScope;
    CHECK\_RET(OH\_JSVM\_OpenEnvScope(env, &envScope));
    JSVM\_HandleScope handlescope;
    CHECK\_RET(OH\_JSVM\_OpenHandleScope(env, &handlescope));
    JSVM\_Value sourcecodevalue;
    CHECK\_RET(OH\_JSVM\_CreateStringUtf8(env, STR\_TASK, strlen(STR\_TASK), &sourcecodevalue));
    JSVM\_Script script;
    CHECK\_RET(OH\_JSVM\_CompileScript(env, sourcecodevalue, nullptr, 0, true, nullptr, &script));
    JSVM\_Value result;
    CHECK\_RET(OH\_JSVM\_RunScript(env, script, &result));
    bool rst = false;
    auto start = std::chrono::system\_clock::now();
    while (true) {
        // 如果任务队列中没有任务启动，则rst设置为false
        CHECK\_RET(OH\_JSVM\_PumpMessageLoop(vm, &rst));
        CHECK\_RET(OH\_JSVM\_PerformMicrotaskCheckpoint(vm));
        // 定时退出
        auto now = std::chrono::system\_clock::now();
        auto cost = std::chrono::duration\_cast<std::chrono::milliseconds>(now - start).count();
        const int timeoutMs = 100;
        if (cost > timeoutMs) {
            break;
        }
    }

    // 关闭并销毁环境和虚拟机
    CHECK\_RET(OH\_JSVM\_CloseHandleScope(env, handlescope));
    CHECK\_RET(OH\_JSVM\_CloseEnvScope(env, envScope));
    CHECK(OH\_JSVM\_DestroyEnv(env));
    CHECK(OH\_JSVM\_CloseVMScope(vm, vm\_scope));
    CHECK(OH\_JSVM\_DestroyVM(vm));
    return 0;
}

预期输出结果：

JSVM API TEST: Called with instance \[object Object\]
JSVM API TEST: Called Finally

#### \[h2\]OH\_JSVM\_SetMicrotaskPolicy

修改微任务执行策略，通过该接口，用户可以将策略设置为 JSVM\_MicrotaskPolicy::JSVM\_MICROTASK\_EXPLICIT 或 JSVM\_MicrotaskPolicy::JSVM\_MICROTASK\_AUTO。默认模式下，微任务的执行策略为 JSVM\_MicrotaskPolicy::JSVM\_MICROTASK\_AUTO。

微任务策略：

*   JSVM\_MicrotaskPolicy::JSVM\_MICROTASK\_EXPLICIT ： 微任务在用户调用 OH\_JSVM\_PerformMicrotaskCheckpoint 后执行
*   JSVM\_MicrotaskPolicy::JSVM\_MICROTASK\_AUTO： 微任务在 JS 调用栈为空时自动执行

cpp 部分代码

// OH\_JSVM\_SetMicrotaskPolicy的样例方法
static int SetMicrotaskPolicy(JSVM\_VM vm, JSVM\_Env env) {
    // 默认或将策略设置为 JSVM\_MICROTASK\_AUTO 的行为
    const char \*scriptEvalMicrotask = R"JS(
        evaluateMicrotask = false;
        Promise.resolve().then(()=>{
            evaluateMicrotask = true;
        });
    )JS";
    JSVM\_Script script;
    JSVM\_Value jsSrc;
    JSVM\_Value result;
    CHECK\_RET(OH\_JSVM\_CreateStringUtf8(env, scriptEvalMicrotask, JSVM\_AUTO\_LENGTH, &jsSrc));
    CHECK\_RET(OH\_JSVM\_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script));
    CHECK\_RET(OH\_JSVM\_RunScript(env, script, &result));
    JSVM\_Value global;
    CHECK\_RET(OH\_JSVM\_GetGlobal(env, &global));
    JSVM\_Value hasEvaluateMicrotask;
    CHECK\_RET(OH\_JSVM\_GetNamedProperty(env, global, "evaluateMicrotask", &hasEvaluateMicrotask));
    bool val = false;
    CHECK\_RET(OH\_JSVM\_GetValueBool(env, hasEvaluateMicrotask, &val));

    OH\_LOG\_INFO(LOG\_APP, "Policy :JSVM\_MICROTASK\_AUTO, evaluateMicrotask : %{public}d", val);

    // 策略设置为 JSVM\_MICROTASK\_EXPLICIT 的行为
    CHECK\_RET(OH\_JSVM\_SetMicrotaskPolicy(vm, JSVM\_MicrotaskPolicy::JSVM\_MICROTASK\_EXPLICIT));
    CHECK\_RET(OH\_JSVM\_RunScript(env, script, &result));
    CHECK\_RET(OH\_JSVM\_GetNamedProperty(env, global, "evaluateMicrotask", &hasEvaluateMicrotask));
    CHECK\_RET(OH\_JSVM\_GetValueBool(env, hasEvaluateMicrotask, &val));
    OH\_LOG\_INFO(
        LOG\_APP,
        "Policy: JSVM\_MICROTASK\_AUTO, evaluateMicrotask before calling OH\_JSVM\_PerformMicrotaskCheckpoint: %{public}d",
        val);

    CHECK\_RET(OH\_JSVM\_PerformMicrotaskCheckpoint(vm));
    CHECK\_RET(OH\_JSVM\_GetNamedProperty(env, global, "evaluateMicrotask", &hasEvaluateMicrotask));
    CHECK\_RET(OH\_JSVM\_GetValueBool(env, hasEvaluateMicrotask, &val));
    OH\_LOG\_INFO(
        LOG\_APP,
        "Policy: JSVM\_MICROTASK\_AUTO, evaluateMicrotask after calling OH\_JSVM\_PerformMicrotaskCheckpoint: %{public}d",
        val);

    return 0;
}

static void RunDemo(JSVM\_VM vm, JSVM\_Env env) {
    if (SetMicrotaskPolicy(vm, env) != 0) {
        OH\_LOG\_INFO(LOG\_APP, "Run Microtask Policy failed");
    }
}

static int32\_t TestJSVM() {
    JSVM\_InitOptions initOptions = {0};
    JSVM\_VM vm;
    JSVM\_Env env = nullptr;
    JSVM\_VMScope vmScope;
    JSVM\_EnvScope envScope;
    JSVM\_HandleScope handleScope;
    JSVM\_Value result;
    // 初始化JavaScript引擎实例
    if (g\_aa == 0) {
        g\_aa++;
        CHECK(OH\_JSVM\_Init(&initOptions));
    }
    // 创建JSVM环境
    CHECK(OH\_JSVM\_CreateVM(nullptr, &vm));
    CHECK(OH\_JSVM\_OpenVMScope(vm, &vmScope));
    CHECK(OH\_JSVM\_CreateEnv(vm, 0, nullptr, &env));
    CHECK\_RET(OH\_JSVM\_OpenEnvScope(env, &envScope));
    CHECK\_RET(OH\_JSVM\_OpenHandleScope(env, &handleScope));

    // 通过script调用测试函数
    RunDemo(vm, env);

    // 销毁JSVM环境
    CHECK\_RET(OH\_JSVM\_CloseHandleScope(env, handleScope));
    CHECK\_RET(OH\_JSVM\_CloseEnvScope(env, envScope));
    CHECK(OH\_JSVM\_DestroyEnv(env));
    CHECK(OH\_JSVM\_CloseVMScope(vm, vmScope));
    CHECK(OH\_JSVM\_DestroyVM(vm));
    return 0;
}

预期输出结果：

Policy :JSVM\_MICROTASK\_AUTO, evaluateMicrotask : 1
Policy :JSVM\_MICROTASK\_AUTO, evaluateMicrotask before calling OH\_JSVM\_PerformMicrotaskCheckpoint: 0
Policy :JSVM\_MICROTASK\_AUTO, evaluateMicrotask after calling OH\_JSVM\_PerformMicrotaskCheckpoint: 1