1# 使用JSVM-API接口创建多个引擎执行JS代码并销毁 2 3## 场景介绍 4 5开发者通过createJsCore方法来创建一个新的JS基础运行时环境,并通过该方法获得一个CoreID,通过evaluateJS方法使用CoreID对应的运行环境来运行JS代码,在JS代码中创建promise并异步执行函数,最后使用releaseJsCore方法来释放CoreID对应的运行环境。 6 7## 使用示例 8 9新建多个JS运行时环境并运行JS代码 10 11 ```cpp 12#include <map> 13#include <mutex> 14#include <deque> 15using namespace std; 16// 定义map管理每个独立vm环境 17static map<int, JSVM_VM *> g_vmMap; 18static map<int, JSVM_Env *> g_envMap; 19static map<int, JSVM_CallbackStruct *> g_callBackStructMap; 20static uint32_t ENVTAG_NUMBER = 0; 21static std::mutex envMapLock; 22 23class Task { 24public: 25 virtual ~Task() = default; 26 virtual void Run() = 0; 27}; 28static map<int, deque<Task *>> g_taskQueueMap; 29 30// 自定义Consoleinfo方法 31static JSVM_Value Consoleinfo(JSVM_Env env, JSVM_CallbackInfo info) { 32 size_t argc = 1; 33 JSVM_Value args[1]; 34 char log[256] = ""; 35 size_t log_length; 36 JSVM_CALL(OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL)); 37 38 JSVM_CALL(OH_JSVM_GetValueStringUtf8(env, args[0], log, 255, &log_length)); 39 log[255] = 0; 40 OH_LOG_INFO(LOG_APP, "JSVM API TEST: %{public}s", log); 41 return nullptr; 42} 43 44// 自定义创建Promise方法用以在JS代码中创建Promise 45static JSVM_Value CreatePromise(JSVM_Env env, JSVM_CallbackInfo info) { 46 OH_LOG_INFO(LOG_APP, "JSVM API TEST: CreatePromise start"); 47 int envID = -1; 48 // 通过当前env获取envID 49 for (auto it = g_envMap.begin(); it != g_envMap.end(); ++it) { 50 if (*it->second == env) { 51 envID = it->first; 52 break; 53 } 54 } 55 if (envID == -1) { 56 OH_LOG_ERROR(LOG_APP, "JSVM API TEST: CreatePromise envID failed"); 57 return nullptr; 58 } 59 JSVM_Value promise; 60 JSVM_Deferred deferred; 61 JSVM_CALL(OH_JSVM_CreatePromise(env, &deferred, &promise)); 62 // 设计ReadTask类用以将promise对象的deferred加入执行队列 63 class ReadTask : public Task { 64 public: 65 ReadTask(JSVM_Env env, JSVM_Deferred deferred, int envNum) : env_(env), envID_(envNum), deferred_(deferred) {} 66 void Run() override { 67 // string str = "TEST RUN OH_JSVM_ResolveDeferred"; 68 int envID = 0; 69 for (auto it = g_envMap.begin(); it != g_envMap.end(); ++it) { 70 if (*it->second == env_) { 71 envID = it->first; 72 break; 73 } 74 } 75 OH_LOG_INFO(LOG_APP, "JSVM API TEST: CreatePromise %{public}d", envID); 76 JSVM_Value result; 77 if (OH_JSVM_CreateInt32(env_, envID, &result) != JSVM_OK) { 78 return; 79 } 80 if (OH_JSVM_ResolveDeferred(env_, deferred_, result) != JSVM_OK) { 81 return; 82 } 83 } 84 85 private: 86 JSVM_Env env_; 87 int envID_; 88 JSVM_Deferred deferred_; 89 }; 90 g_taskQueueMap[envID].push_back(new ReadTask(env, deferred, envID)); 91 OH_LOG_INFO(LOG_APP, "JSVM API TEST: CreatePromise end"); 92 return promise; 93} 94 95// 自定义Add方法 96static JSVM_Value Add(JSVM_Env env, JSVM_CallbackInfo info) { 97 size_t argc = 2; 98 JSVM_Value args[2]; 99 JSVM_CALL(OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL)); 100 double num1, num2; 101 JSVM_CALL(OH_JSVM_GetValueDouble(env, args[0], &num1)); 102 JSVM_CALL(OH_JSVM_GetValueDouble(env, args[1], &num2)); 103 JSVM_Value sum = nullptr; 104 JSVM_CALL(OH_JSVM_CreateDouble(env, num1 + num2, &sum)); 105 return sum; 106} 107 108// 自定义AssertEqual方法 109static JSVM_Value AssertEqual(JSVM_Env env, JSVM_CallbackInfo info) { 110 size_t argc = 2; 111 JSVM_Value args[2]; 112 JSVM_CALL(OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL)); 113 114 bool isStrictEquals = false; 115 JSVM_CALL(OH_JSVM_StrictEquals(env, args[0], args[1], &isStrictEquals)); 116 117 if (isStrictEquals) { 118 OH_LOG_INFO(LOG_APP, "JSVM API TEST RESULT: PASS"); 119 } else { 120 OH_LOG_INFO(LOG_APP, "JSVM API TEST RESULT: FAILED"); 121 } 122 return nullptr; 123} 124 125static int fromOHStringValue(JSVM_Env &env, JSVM_Value &value, std::string &result) { 126 size_t size; 127 CHECK_RET(OH_JSVM_GetValueStringUtf8(env, value, nullptr, 0, &size)); 128 char resultStr[size + 1]; 129 CHECK_RET(OH_JSVM_GetValueStringUtf8(env, value, resultStr, size + 1, &size)); 130 result = resultStr; 131 return 0; 132} 133 134// 提供创建JSVM运行环境的对外接口并返回对应唯一ID 135static int CreateJsCore(uint32_t *result) { 136 OH_LOG_INFO(LOG_APP, "JSVM CreateJsCore START"); 137 g_taskQueueMap[ENVTAG_NUMBER] = deque<Task *>{}; 138 139 if (g_aa == 0) { 140 JSVM_InitOptions init_options; 141 memset(&init_options, 0, sizeof(init_options)); 142 CHECK(OH_JSVM_Init(&init_options) == JSVM_OK); 143 g_aa++; 144 } 145 std::lock_guard<std::mutex> lock_guard(envMapLock); 146 147 // 虚拟机实例 148 g_vmMap[ENVTAG_NUMBER] = new JSVM_VM; 149 JSVM_CreateVMOptions options; 150 JSVM_VMScope vmScope; 151 memset(&options, 0, sizeof(options)); 152 CHECK(OH_JSVM_CreateVM(&options, g_vmMap[ENVTAG_NUMBER]) == JSVM_OK); 153 CHECK(OH_JSVM_OpenVMScope(*g_vmMap[ENVTAG_NUMBER], &vmScope) == JSVM_OK); 154 155 // 新环境 156 g_envMap[ENVTAG_NUMBER] = new JSVM_Env; 157 g_callBackStructMap[ENVTAG_NUMBER] = new JSVM_CallbackStruct[4]; 158 159 // 注册用户提供的本地函数的回调函数指针和数据,通过JSVM-API暴露给js 160 for (int i = 0; i < 4; i++) { 161 g_callBackStructMap[ENVTAG_NUMBER][i].data = nullptr; 162 } 163 g_callBackStructMap[ENVTAG_NUMBER][0].callback = Consoleinfo; 164 g_callBackStructMap[ENVTAG_NUMBER][1].callback = Add; 165 g_callBackStructMap[ENVTAG_NUMBER][2].callback = AssertEqual; 166 g_callBackStructMap[ENVTAG_NUMBER][3].callback = CreatePromise; 167 JSVM_PropertyDescriptor descriptors[] = { 168 {"consoleinfo", NULL, &g_callBackStructMap[ENVTAG_NUMBER][0], NULL, NULL, NULL, JSVM_DEFAULT}, 169 {"add", NULL, &g_callBackStructMap[ENVTAG_NUMBER][1], NULL, NULL, NULL, JSVM_DEFAULT}, 170 {"assertEqual", NULL, &g_callBackStructMap[ENVTAG_NUMBER][2], NULL, NULL, NULL, JSVM_DEFAULT}, 171 {"createPromise", NULL, &g_callBackStructMap[ENVTAG_NUMBER][3], NULL, NULL, NULL, JSVM_DEFAULT}, 172 }; 173 CHECK(OH_JSVM_CreateEnv(*g_vmMap[ENVTAG_NUMBER], sizeof(descriptors) / sizeof(descriptors[0]), descriptors, 174 g_envMap[ENVTAG_NUMBER]) == JSVM_OK); 175 CHECK(OH_JSVM_CloseVMScope(*g_vmMap[ENVTAG_NUMBER], vmScope) == JSVM_OK); 176 177 OH_LOG_INFO(LOG_APP, "JSVM CreateJsCore END"); 178 *result = ENVTAG_NUMBER; 179 ENVTAG_NUMBER++; 180 return 0; 181} 182 183// 对外提供释放JSVM环境接口,通过envId释放对应环境 184static int ReleaseJsCore(uint32_t coreEnvId) { 185 OH_LOG_INFO(LOG_APP, "JSVM ReleaseJsCore START"); 186 CHECK(g_envMap.count(coreEnvId) != 0 && g_envMap[coreEnvId] != nullptr); 187 188 std::lock_guard<std::mutex> lock_guard(envMapLock); 189 190 CHECK(OH_JSVM_DestroyEnv(*g_envMap[coreEnvId]) == JSVM_OK); 191 g_envMap[coreEnvId] = nullptr; 192 g_envMap.erase(coreEnvId); 193 CHECK(OH_JSVM_DestroyVM(*g_vmMap[coreEnvId]) == JSVM_OK); 194 g_vmMap[coreEnvId] = nullptr; 195 g_vmMap.erase(coreEnvId); 196 delete[] g_callBackStructMap[coreEnvId]; 197 g_callBackStructMap[coreEnvId] = nullptr; 198 g_callBackStructMap.erase(coreEnvId); 199 g_taskQueueMap.erase(coreEnvId); 200 201 OH_LOG_INFO(LOG_APP, "JSVM ReleaseJsCore END"); 202 return 0; 203} 204 205static std::mutex mutexLock; 206// 对外提供执行JS代码接口,通过coreID在对应的JSVN环境中执行JS代码 207static int EvaluateJS(uint32_t envId, const char *source, std::string &res) { 208 OH_LOG_INFO(LOG_APP, "JSVM EvaluateJS START"); 209 210 CHECK(g_envMap.count(envId) != 0 && g_envMap[envId] != nullptr); 211 212 JSVM_Env env = *g_envMap[envId]; 213 JSVM_VM vm = *g_vmMap[envId]; 214 JSVM_VMScope vmScope; 215 JSVM_EnvScope envScope; 216 JSVM_HandleScope handleScope; 217 JSVM_Value result; 218 219 std::lock_guard<std::mutex> lock_guard(mutexLock); 220 { 221 // 创建JSVM环境 222 CHECK_RET(OH_JSVM_OpenVMScope(vm, &vmScope)); 223 CHECK_RET(OH_JSVM_OpenEnvScope(*g_envMap[envId], &envScope)); 224 CHECK_RET(OH_JSVM_OpenHandleScope(*g_envMap[envId], &handleScope)); 225 226 // 通过script调用测试函数 227 JSVM_Script script; 228 JSVM_Value jsSrc; 229 CHECK_RET(OH_JSVM_CreateStringUtf8(env, source, JSVM_AUTO_LENGTH, &jsSrc)); 230 CHECK_RET(OH_JSVM_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script)); 231 CHECK_RET(OH_JSVM_RunScript(env, script, &result)); 232 233 JSVM_ValueType type; 234 CHECK_RET(OH_JSVM_Typeof(env, result, &type)); 235 OH_LOG_INFO(LOG_APP, "JSVM API TEST type: %{public}d", type); 236 // Execute tasks in the current env event queue 237 while (!g_taskQueueMap[envId].empty()) { 238 auto task = g_taskQueueMap[envId].front(); 239 g_taskQueueMap[envId].pop_front(); 240 task->Run(); 241 delete task; 242 } 243 244 if (type == JSVM_STRING) { 245 CHECK(fromOHStringValue(env, result, res) != -1); 246 } else if (type == JSVM_BOOLEAN) { 247 bool ret = false; 248 CHECK_RET(OH_JSVM_GetValueBool(env, result, &ret)); 249 ret ? res = "true" : res = "false"; 250 } else if (type == JSVM_NUMBER) { 251 int32_t num; 252 CHECK_RET(OH_JSVM_GetValueInt32(env, result, &num)); 253 res = std::to_string(num); 254 } else if (type == JSVM_OBJECT) { 255 JSVM_Value objResult; 256 CHECK_RET(OH_JSVM_JsonStringify(env, result, &objResult)); 257 CHECK(fromOHStringValue(env, objResult, res) != -1); 258 } 259 } 260 { 261 bool aal = false; 262 CHECK_RET(OH_JSVM_PumpMessageLoop(*g_vmMap[envId], &aal)); 263 CHECK_RET(OH_JSVM_PerformMicrotaskCheckpoint(*g_vmMap[envId])); 264 CHECK_RET(OH_JSVM_CloseHandleScope(*g_envMap[envId], handleScope)); 265 CHECK_RET(OH_JSVM_CloseEnvScope(*g_envMap[envId], envScope)); 266 CHECK_RET(OH_JSVM_CloseVMScope(*g_vmMap[envId], vmScope)); 267 } 268 OH_LOG_INFO(LOG_APP, "JSVM EvaluateJS END"); 269 return 0; 270} 271 272static int32_t TestJSVM() { 273 const char source1[] = "{\ 274 let a = \"hello World\";\ 275 consoleinfo(a);\ 276 const mPromise = createPromise();\ 277 mPromise.then((result) => {\ 278 assertEqual(result, 0);\ 279 });\ 280 a;\ 281 };"; 282 283 const char source2[] = "{\ 284 let a = \"second hello\";\ 285 consoleinfo(a);\ 286 let b = add(99, 1);\ 287 assertEqual(100, b);\ 288 assertEqual(add(99, 1), 100);\ 289 createPromise().then((result) => {\ 290 assertEqual(result, 1);\ 291 });\ 292 a;\ 293 };"; 294 295 // 创建首个运行环境,并绑定TS回调 296 uint32_t coreId1; 297 CHECK(CreateJsCore(&coreId1) == 0); 298 OH_LOG_INFO(LOG_APP, "TEST coreId: %{public}d", coreId1); 299 // 在首个运行环境中执行JS代码 300 std::string result1; 301 CHECK(EvaluateJS(coreId1, source1, result1) == 0); 302 OH_LOG_INFO(LOG_APP, "TEST evaluateJS: %{public}s", result1.c_str()); 303 304 // 创建第二个运行环境,并绑定TS回调 305 uint32_t coreId2; 306 CHECK(CreateJsCore(&coreId2) == 0); 307 OH_LOG_INFO(LOG_APP, "TEST coreId: %{public}d", coreId2); 308 // 在第二个运行环境中执行JS代码 309 std::string result2; 310 CHECK(EvaluateJS(coreId2, source2, result2) == 0); 311 OH_LOG_INFO(LOG_APP, "TEST evaluateJS: %{public}s", result2.c_str()); 312 313 // 释放首个运行环境 314 CHECK(ReleaseJsCore(coreId1) == 0); 315 // 释放第二个运行环境 316 CHECK(ReleaseJsCore(coreId2) == 0); 317 OH_LOG_INFO(LOG_APP, "Test NAPI end"); 318 319 return 0; 320} 321 ``` 322