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