1# 使用JSVM-API接口进行任务队列相关开发
2
3## 简介
4
5在虚拟机内部启动任务队列的运行,检查是否有微任务在队列中等待,这个任务队列可以由外部事件循环执行。
6
7## 基本概念
8
9- **任务队列**:管理异步任务的调度和执行,确保任务按顺序处理。
10- **微任务**:微任务是一种任务调度机制,主要用于处理那些需要尽快执行的较小任务,它们通常具有较高的优先级。
11
12## 接口说明
13
14| 接口 | 功能说明 |
15| -------- | -------- |
16|OH_JSVM_PumpMessageLoop| 启动任务队列的运行 |
17|OH_JSVM_PerformMicrotaskCheckpoint| 执行任务队列里的微任务 |
18## 使用示例
19
20JSVM-API接口开发流程参考[使用JSVM-API实现JS与C/C++语言交互开发流程](use-jsvm-process.md),本文仅对接口对应C++相关代码进行展示。
21
22### OH_JSVM_PumpMessageLoop && OH_JSVM_PerformMicrotaskCheckpoint
23
24启动任务队列,执行任务。
25
26cpp代码
27
28```cpp
29#include <chrono>
30#include <string.h>
31
32
33// 待执行的js代码
34static const char *STR_TASK = R"JS(
35    // wasm 字节码 (以add 模块为例)
36    // 以下 wasmBuffer 对应的 wasm 字节码文本格式如下所示,只包含了一个函数 add
37    // (module
38    //   (func $add (param $lhs i32) (param $rhs i32) (result i32)
39    //     local.get $lhs
40    //     local.get $rhs
41    //     i32.add
42    //   )
43    //   (export "add" (func $add))
44    // )
45    var wasmBytes = new Uint8Array([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01,
46                                       0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07,
47                                       0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01,
48                                       0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b]);
49
50    var p = WebAssembly.instantiate(wasmBytes, {});
51    p.then((result) => {
52        consoleinfo("Called with instance " + result);
53    });
54    p.finally(() => {
55       consoleinfo("Called Finally");
56    });
57)JS";
58
59// 保证js代码中的打印信息可以正常输出
60static JSVM_Value ConsoleInfo(JSVM_Env env, JSVM_CallbackInfo info) {
61    size_t argc = 1;
62    JSVM_Value args[1];
63    char log[256] = "";
64    size_t logLength;
65    JSVM_CALL(OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL));
66
67    OH_JSVM_GetValueStringUtf8(env, args[0], log, 255, &logLength);
68    log[255] = 0;
69    OH_LOG_INFO(LOG_APP, "JSVM API TEST: %{public}s", log);
70    return nullptr;
71}
72
73// 注册consoleinfo的方法
74JSVM_CallbackStruct param[] = {
75    {.data = nullptr, .callback = ConsoleInfo},
76};
77JSVM_PropertyDescriptor descriptor[] = {
78    {"consoleinfo", NULL, &param[0], NULL, NULL, NULL, JSVM_DEFAULT},
79};
80
81static int32_t TestJSVM() {
82    JSVM_InitOptions init_options;
83    memset(&init_options, 0, sizeof(init_options));
84    if (g_aa == 0) {
85        OH_JSVM_Init(&init_options);
86        g_aa++;
87    }
88    // 创建JavaScript虚拟机实例,打开虚拟机作用域
89    JSVM_VM vm;
90    JSVM_CreateVMOptions options;
91    memset(&options, 0, sizeof(options));
92    CHECK(OH_JSVM_CreateVM(&options, &vm));
93    JSVM_VMScope vm_scope;
94    CHECK(OH_JSVM_OpenVMScope(vm, &vm_scope));
95
96    JSVM_Env env;
97    CHECK(OH_JSVM_CreateEnv(vm, sizeof(descriptor) / sizeof(descriptor[0]), descriptor, &env));
98    JSVM_EnvScope envScope;
99    CHECK_RET(OH_JSVM_OpenEnvScope(env, &envScope));
100    JSVM_HandleScope handlescope;
101    CHECK_RET(OH_JSVM_OpenHandleScope(env, &handlescope));
102    JSVM_Value sourcecodevalue;
103    CHECK_RET(OH_JSVM_CreateStringUtf8(env, STR_TASK, strlen(STR_TASK), &sourcecodevalue));
104    JSVM_Script script;
105    CHECK_RET(OH_JSVM_CompileScript(env, sourcecodevalue, nullptr, 0, true, nullptr, &script));
106    JSVM_Value result;
107    CHECK_RET(OH_JSVM_RunScript(env, script, &result));
108    bool rst = false;
109    auto start = std::chrono::system_clock::now();
110    while (true) {
111        // 如果任务队列中没有任务启动,则rst设置为false
112        CHECK_RET(OH_JSVM_PumpMessageLoop(vm, &rst));
113        CHECK_RET(OH_JSVM_PerformMicrotaskCheckpoint(vm));
114        // 定时退出
115        auto now = std::chrono::system_clock::now();
116        auto cost = std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count();
117        if (cost > 100) {
118            break;
119        }
120    }
121
122    // 关闭并销毁环境和虚拟机
123    CHECK_RET(OH_JSVM_CloseHandleScope(env, handlescope));
124    CHECK_RET(OH_JSVM_CloseEnvScope(env, envScope));
125    CHECK(OH_JSVM_DestroyEnv(env));
126    CHECK(OH_JSVM_CloseVMScope(vm, vm_scope));
127    CHECK(OH_JSVM_DestroyVM(vm));
128    return 0;
129}
130
131```
132预期输出结果
133```
134JSVM API TEST: Called with instance [object Object]
135JSVM API TEST: Called Finally
136```
137### OH_JSVM_SetMicrotaskPolicy
138修改微任务执行策略,通过该接口,用户可以将策略设置为 JSVM_MicrotaskPolicy::JSVM_MICROTASK_EXPLICIT 或 JSVM_MicrotaskPolicy::JSVM_MICROTASK_AUTO。默认模式下,微任务的执行策略为 JSVM_MicrotaskPolicy::JSVM_MICROTASK_AUTO。
139
140微任务策略:
141- JSVM_MicrotaskPolicy::JSVM_MICROTASK_EXPLICIT : 微任务在用户调用 OH_JSVM_PerformMicrotaskCheckpoint 后执行
142- JSVM_MicrotaskPolicy::JSVM_MICROTASK_AUTO: 微任务在 JS 调用栈为空时自动执行
143
144cpp 部分代码
145
146```
147// OH_JSVM_SetMicrotaskPolicy的样例方法
148static int SetMicrotaskPolicy(JSVM_VM vm, JSVM_Env env) {
149    // 默认或将策略设置为 JSVM_MICROTASK_AUTO 的行为
150    const char *scriptEvalMicrotask = R"JS(
151        evaluateMicrotask = false;
152        Promise.resolve().then(()=>{
153            evaluateMicrotask = true;
154        });
155    )JS";
156    JSVM_Script script;
157    JSVM_Value jsSrc;
158    JSVM_Value result;
159    CHECK_RET(OH_JSVM_CreateStringUtf8(env, scriptEvalMicrotask, JSVM_AUTO_LENGTH, &jsSrc));
160    CHECK_RET(OH_JSVM_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script));
161    CHECK_RET(OH_JSVM_RunScript(env, script, &result));
162    JSVM_Value global;
163    CHECK_RET(OH_JSVM_GetGlobal(env, &global));
164    JSVM_Value hasEvaluateMicrotask;
165    CHECK_RET(OH_JSVM_GetNamedProperty(env, global, "evaluateMicrotask", &hasEvaluateMicrotask));
166    bool val;
167    CHECK_RET(OH_JSVM_GetValueBool(env, hasEvaluateMicrotask, &val));
168
169    OH_LOG_INFO(LOG_APP, "Policy :JSVM_MICROTASK_AUTO, evaluateMicrotask : %{public}d", val);
170
171    // 策略设置为 JSVM_MICROTASK_EXPLICIT 的行为
172    CHECK_RET(OH_JSVM_SetMicrotaskPolicy(vm, JSVM_MicrotaskPolicy::JSVM_MICROTASK_EXPLICIT));
173    CHECK_RET(OH_JSVM_RunScript(env, script, &result));
174    CHECK_RET(OH_JSVM_GetNamedProperty(env, global, "evaluateMicrotask", &hasEvaluateMicrotask));
175    CHECK_RET(OH_JSVM_GetValueBool(env, hasEvaluateMicrotask, &val));
176    OH_LOG_INFO(
177        LOG_APP,
178        "Policy :JSVM_MICROTASK_AUTO, evaluateMicrotask before calling OH_JSVM_PerformMicrotaskCheckpoint: %{public}d",
179        val);
180
181    CHECK_RET(OH_JSVM_PerformMicrotaskCheckpoint(vm));
182    CHECK_RET(OH_JSVM_GetNamedProperty(env, global, "evaluateMicrotask", &hasEvaluateMicrotask));
183    CHECK_RET(OH_JSVM_GetValueBool(env, hasEvaluateMicrotask, &val));
184    OH_LOG_INFO(
185        LOG_APP,
186        "Policy :JSVM_MICROTASK_AUTO, evaluateMicrotask after calling OH_JSVM_PerformMicrotaskCheckpoint: %{public}d",
187        val);
188
189    return 0;
190}
191
192static void RunDemo(JSVM_VM vm, JSVM_Env env) {
193    if (SetMicrotaskPolicy(vm, env) != 0) {
194        OH_LOG_INFO(LOG_APP, "Run Microtask Policy failed");
195    }
196}
197
198static int32_t TestJSVM() {
199    JSVM_InitOptions initOptions = {0};
200    JSVM_VM vm;
201    JSVM_Env env = nullptr;
202    JSVM_VMScope vmScope;
203    JSVM_EnvScope envScope;
204    JSVM_HandleScope handleScope;
205    JSVM_Value result;
206    // 初始化JavaScript引擎实例
207    if (g_aa == 0) {
208        g_aa++;
209        CHECK(OH_JSVM_Init(&initOptions));
210    }
211    // 创建JSVM环境
212    CHECK(OH_JSVM_CreateVM(nullptr, &vm));
213    CHECK(OH_JSVM_CreateEnv(vm, 0, nullptr, &env));
214    CHECK(OH_JSVM_OpenVMScope(vm, &vmScope));
215    CHECK_RET(OH_JSVM_OpenEnvScope(env, &envScope));
216    CHECK_RET(OH_JSVM_OpenHandleScope(env, &handleScope));
217
218    // 通过script调用测试函数
219    RunDemo(vm, env);
220
221    // 销毁JSVM环境
222    CHECK_RET(OH_JSVM_CloseHandleScope(env, handleScope));
223    CHECK_RET(OH_JSVM_CloseEnvScope(env, envScope));
224    CHECK(OH_JSVM_CloseVMScope(vm, vmScope));
225    CHECK(OH_JSVM_DestroyEnv(env));
226    CHECK(OH_JSVM_DestroyVM(vm));
227    return 0;
228}
229```
230
231预期输出结果
232```
233Policy :JSVM_MICROTASK_AUTO, evaluateMicrotask : 1
234Policy :JSVM_MICROTASK_AUTO, evaluateMicrotask before calling OH_JSVM_PerformMicrotaskCheckpoint: 0
235Policy :JSVM_MICROTASK_AUTO, evaluateMicrotask after calling OH_JSVM_PerformMicrotaskCheckpoint: 1
236```
237