1# Creating and Destroying JSVMs Using JSVM-API 2 3## When to Use 4 5Use **createJsCore** to create a JavaScript virtual machine (JSVM), which a runtime environment for executing JS code. The **createJsCore** returns a core ID, which uniquely identifies a VM. 6 7Use **evaluateJS** to run JS code in the VM of the specified core ID and define a promise in the JS code to asynchronously invoke the callback set in TS. 8 9Use **releaseJsCore** to release a JSVM. 10 11## Example 12 131. Declare APIs and configure compile settings. 14 15**Declare the APIs.** 16 17 ```ts 18 // index.d.ts 19 export const createJsCore: (fun: Function) => number; 20 export const releaseJsCore: (a: number) => void; 21 export const evaluateJS: (a: number, str: string) => string; 22 ``` 23 24**Configure compile settings.** 25 26 ``` 27 // CMakeLists.txt 28 # the minimum version of CMake. 29 cmake_minimum_required(VERSION 3.4.1) 30 project(MyApplication) 31 32 set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) 33 34 if(DEFINED PACKAGE_FIND_FILE) 35 include(${PACKAGE_FIND_FILE}) 36 endif() 37 38 include_directories(${NATIVERENDER_ROOT_PATH} 39 ${NATIVERENDER_ROOT_PATH}/include) 40 41 add_library(entry SHARED create_jsvm_runtime.cpp) 42 target_link_libraries(entry PUBLIC libace_napi.z.so libjsvm.so libhilog_ndk.z.so) 43 ``` 44 452. Create multiple JS runtime environments and run JS code. 46 47 ```cpp 48 // create_jsvm_runtime.cpp 49 #include "napi/native_api.h" 50 #include "ark_runtime/jsvm.h" 51 #include <bits/alltypes.h> 52 #include <deque> 53 #include <map> 54 #include <unistd.h> 55 #include <hilog/log.h> 56 #include <cstring> 57 #include <string> 58 #include <vector> 59 #include <sstream> 60 61 #define LOG_TAG "TEST_TAG" 62 // Obtain and throw the last error message. Use OH_JSVM_GetLastErrorInfo to obtain error information. 63 // If there is error information and no suspended exception, use OH_JSVM_ThrowError to throw an error. 64 #define GET_AND_THROW_LAST_ERROR(env) \ 65 do { \ 66 const JSVM_ExtendedErrorInfo* errorInfo = nullptr; \ 67 OH_JSVM_GetLastErrorInfo((env), &errorInfo); \ 68 bool isPending = false; \ 69 OH_JSVM_IsExceptionPending((env), &isPending); \ 70 JSVM_Value error; \ 71 if (isPending && JSVM_OK == OH_JSVM_GetAndClearLastException((env), &error)) { \ 72 \ 73 JSVM_Value stack; \ 74 OH_JSVM_GetNamedProperty((env), error, "stack", &stack); \ 75 \ 76 JSVM_Value message; \ 77 OH_JSVM_GetNamedProperty((env), error, "message", &message); \ 78 \ 79 char stackstr[256]; \ 80 OH_JSVM_GetValueStringUtf8(env, stack, stackstr, 256, nullptr); \ 81 OH_LOG_INFO(LOG_APP, "JSVM error stack: %{public}s", stackstr); \ 82 char messagestr[256]; \ 83 OH_JSVM_GetValueStringUtf8(env, message, messagestr, 256, nullptr); \ 84 OH_LOG_INFO(LOG_APP, "JSVM error message: %{public}s", messagestr); \ 85 } \ 86 if (!isPending && errorInfo != nullptr) { \ 87 const char* errorMessage = \ 88 errorInfo->errorMessage != nullptr ? errorInfo->errorMessage : "empty error message"; \ 89 OH_JSVM_ThrowError((env), nullptr, errorMessage); \ 90 } \ 91 } while (0) 92 93 // Call theCall and check whether the return value is JSVM_OK. 94 // If no, call GET_AND_THROW_LAST_ERROR to process the error and return retVal. 95 #define JSVM_CALL_BASE(env, theCall, retVal) \ 96 do { \ 97 if ((theCall) != JSVM_OK) { \ 98 GET_AND_THROW_LAST_ERROR((env)); \ 99 return retVal; \ 100 } \ 101 } while (0) 102 103 // Simplified version of JSVM_CALL_BASE. nullptr is returned. 104 #define JSVM_CALL(env, theCall) JSVM_CALL_BASE(env, theCall, nullptr) 105 106 using namespace std; 107 // Define a map to manage each independent VM. 108 static map<int, JSVM_VM*> g_vmMap; 109 static map<int, JSVM_Env*> g_envMap; 110 static map<int, napi_env> g_napiEnvMap; 111 static map<int, napi_ref> g_callBackMap; 112 static map<int, JSVM_CallbackStruct*> g_callBackStructMap; 113 static uint32_t ENVTAG_NUMBER = 0; 114 static std::mutex envMapLock; 115 static int aa = 0; 116 117 class Task { 118 public: 119 virtual ~Task() = default; 120 virtual void Run() = 0; 121 }; 122 static map<int, deque<Task *>> g_taskQueueMap; 123 124 // Customize Consoleinfo. 125 static JSVM_Value Consoleinfo(JSVM_Env env, JSVM_CallbackInfo info) { 126 size_t argc = 1; 127 JSVM_Value args[1]; 128 char log[256] = ""; 129 size_t log_length; 130 OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL); 131 132 OH_JSVM_GetValueStringUtf8(env, args[0], log, 255, &log_length); 133 log[255] = 0; 134 OH_LOG_INFO(LOG_APP, "JSVM API TEST: %{public}s", log); 135 return nullptr; 136 } 137 138 // Create a promise method, which is used to create a promise in JS code. 139 static JSVM_Value CreatePromise(JSVM_Env env, JSVM_CallbackInfo info) { 140 OH_LOG_INFO(LOG_APP, "JSVM API TEST: CreatePromise start"); 141 int envID = 0; 142 // Obtain envID of the current env. 143 for (auto it = g_envMap.begin(); it != g_envMap.end(); ++it) { 144 if (*it->second == env) { 145 envID = it->first; 146 break; 147 } 148 } 149 if (envID == -1) { 150 OH_LOG_INFO(LOG_APP, "JSVM API TEST: CreatePromise envID faild"); 151 return nullptr; 152 } 153 JSVM_Value promise; 154 JSVM_Deferred deferred; 155 OH_JSVM_CreatePromise(env, &deferred, &promise); 156 // Define a ReadTask class to add deferred of the promise object to the execution queue. 157 class ReadTask : public Task { 158 public: 159 ReadTask(JSVM_Env env, JSVM_Deferred deferred, int envNum) : env_(env), envID_(envNum), deferred_(deferred) {} 160 void Run() override { 161 //string str = "TEST RUN OH_JSVM_ResolveDeferred"; 162 int envID = 0; 163 for (auto it = g_envMap.begin(); it != g_envMap.end(); ++it) { 164 if (*it->second == env_) { 165 envID = it->first; 166 break; 167 } 168 } 169 OH_LOG_INFO(LOG_APP, "JSVM API TEST: CreatePromise %{public}d", envID); 170 JSVM_Value result; 171 OH_JSVM_CreateInt32(env_, envID, &result); 172 OH_JSVM_ResolveDeferred(env_, deferred_, result); 173 } 174 private: 175 JSVM_Env env_; 176 int envID_; 177 JSVM_Deferred deferred_; 178 }; 179 g_taskQueueMap[envID].push_back(new ReadTask(env, deferred, envID)); 180 OH_LOG_INFO(LOG_APP, "JSVM API TEST: CreatePromise end"); 181 return promise; 182 } 183 184 // Customize the Add method. 185 static JSVM_Value Add(JSVM_Env env, JSVM_CallbackInfo info) { 186 size_t argc = 2; 187 JSVM_Value args[2]; 188 OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL); 189 double num1, num2; 190 OH_JSVM_GetValueDouble(env, args[0], &num1); 191 OH_JSVM_GetValueDouble(env, args[1], &num2); 192 JSVM_Value sum = nullptr; 193 OH_JSVM_CreateDouble(env, num1 + num2, &sum); 194 return sum; 195 } 196 197 // Customize the AssertEqual method. 198 static JSVM_Value AssertEqual(JSVM_Env env, JSVM_CallbackInfo info) { 199 size_t argc = 2; 200 JSVM_Value args[2]; 201 JSVM_CALL(env, OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL)); 202 203 bool isStrictEquals = false; 204 OH_JSVM_StrictEquals(env, args[0], args[1], &isStrictEquals); 205 206 if (isStrictEquals) { 207 OH_LOG_INFO(LOG_APP, "JSVM API TEST RESULT: PASS"); 208 } else { 209 OH_LOG_INFO(LOG_APP, "JSVM API TEST RESULT: FAILED"); 210 } 211 return nullptr; 212 } 213 214 // Invoke the native callback passed by TS. 215 static JSVM_Value OnJSResultCallback(JSVM_Env env, JSVM_CallbackInfo info) { 216 size_t argc = 3; 217 JSVM_Value args[3]; 218 JSVM_CALL(env, OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL)); 219 int callId = 0; 220 OH_JSVM_GetValueInt32(env, args[0], &callId); 221 napi_value callArgs[2] = {nullptr, nullptr}; 222 size_t size; 223 size_t size1; 224 225 OH_JSVM_GetValueStringUtf8(env, args[1], nullptr, 0, &size); 226 char Str1[size + 1]; 227 OH_JSVM_GetValueStringUtf8(env, args[1], Str1, size + 1, &size); 228 229 OH_JSVM_GetValueStringUtf8(env, args[2], nullptr, 0, &size1); 230 char Str2[size1 + 1]; 231 OH_JSVM_GetValueStringUtf8(env, args[2], Str2, size1 + 1, &size1); 232 233 napi_create_string_utf8(g_napiEnvMap[callId], Str1, size + 1, &callArgs[0]); 234 napi_create_string_utf8(g_napiEnvMap[callId], Str2, size1 + 1, &callArgs[1]); 235 napi_value callback = nullptr; 236 // Obtain the TS callback, which is passed in when the JSVM is created, based on the call ID. 237 napi_get_reference_value(g_napiEnvMap[callId], g_callBackMap[callId], &callback); 238 napi_value ret; 239 // Execute the TS callback. 240 napi_call_function(g_napiEnvMap[callId], nullptr, callback, 2, callArgs, &ret); 241 char retStr[256]; 242 napi_get_value_string_utf8(g_napiEnvMap[callId], ret, retStr, 256, &size); 243 244 JSVM_Value returnVal; 245 OH_JSVM_CreateStringUtf8(env, retStr, JSVM_AUTO_LENGTH, &returnVal); 246 return returnVal; 247 } 248 249 std::string napiValueToString(napi_env env, napi_value nValue) { 250 size_t buffLen = 0; 251 napi_get_value_string_utf8(env, nValue, nullptr, 0, &buffLen); 252 char buffer[buffLen + 1]; 253 napi_get_value_string_utf8(env, nValue, buffer, buffLen + 1, &buffLen); 254 255 return buffer; 256 } 257 258 static std::string fromOHStringValue(JSVM_Env &env, JSVM_Value &value) { 259 size_t size; 260 JSVM_Status status; 261 status = OH_JSVM_GetValueStringUtf8(env, value, nullptr, 0, &size); 262 char resultStr[size + 1]; 263 status = OH_JSVM_GetValueStringUtf8(env, value, resultStr, size + 1, &size); 264 return resultStr; 265 } 266 267 static void CreateArkJSContext() { 268 JSVM_Status status; 269 JSVM_InitOptions init_options; 270 memset(&init_options, 0, sizeof(init_options)); 271 if (aa == 0) { 272 OH_JSVM_Init(&init_options); 273 aa++; 274 } 275 276 // VM instance. 277 g_vmMap[ENVTAG_NUMBER] = new JSVM_VM; 278 JSVM_CreateVMOptions options; 279 memset(&options, 0, sizeof(options)); 280 status = OH_JSVM_CreateVM(&options, g_vmMap[ENVTAG_NUMBER]); 281 JSVM_VMScope vmScope; 282 OH_JSVM_OpenVMScope(*g_vmMap[ENVTAG_NUMBER], &vmScope); 283 284 // New environment. 285 g_envMap[ENVTAG_NUMBER] = new JSVM_Env; 286 g_callBackStructMap[ENVTAG_NUMBER] = new JSVM_CallbackStruct[5]; 287 288 // Register the pointers to the native callbacks and data provided by the user and expose them to JS code through JSVM-API. 289 for (int i = 0; i < 5; i++) { 290 g_callBackStructMap[ENVTAG_NUMBER][i].data = nullptr; 291 } 292 g_callBackStructMap[ENVTAG_NUMBER][0].callback = Consoleinfo; 293 g_callBackStructMap[ENVTAG_NUMBER][1].callback = Add; 294 g_callBackStructMap[ENVTAG_NUMBER][2].callback = AssertEqual; 295 g_callBackStructMap[ENVTAG_NUMBER][3].callback = OnJSResultCallback; 296 g_callBackStructMap[ENVTAG_NUMBER][4].callback = CreatePromise; 297 JSVM_PropertyDescriptor descriptors[] = { 298 {"consoleinfo", NULL, &g_callBackStructMap[ENVTAG_NUMBER][0], NULL, NULL, NULL, JSVM_DEFAULT}, 299 {"add", NULL, &g_callBackStructMap[ENVTAG_NUMBER][1], NULL, NULL, NULL, JSVM_DEFAULT}, 300 {"assertEqual", NULL, &g_callBackStructMap[ENVTAG_NUMBER][2], NULL, NULL, NULL, JSVM_DEFAULT}, 301 {"onJSResultCallback", NULL, &g_callBackStructMap[ENVTAG_NUMBER][3], NULL, NULL, NULL, JSVM_DEFAULT}, 302 {"createPromise", NULL, &g_callBackStructMap[ENVTAG_NUMBER][4], NULL, NULL, NULL, JSVM_DEFAULT}, 303 }; 304 status = OH_JSVM_CreateEnv(*g_vmMap[ENVTAG_NUMBER], sizeof(descriptors) / sizeof(descriptors[0]), descriptors, g_envMap[ENVTAG_NUMBER]); 305 OH_JSVM_CloseVMScope(*g_vmMap[ENVTAG_NUMBER], vmScope); 306 } 307 308 // Provide an external interface for creating the JSVM and return the unique ID. 309 static napi_value CreateJsCore(napi_env env1, napi_callback_info info) { 310 OH_LOG_ERROR(LOG_APP, "JSVM CreateJsCore START"); 311 size_t argc = 1; 312 napi_value argv[1]; 313 napi_get_cb_info(env1, info, &argc, argv, nullptr, nullptr); 314 if (argc < 1) { 315 OH_LOG_ERROR(LOG_APP, "JSVM CreateJsCore the number of params must be one"); 316 return nullptr; 317 } 318 g_napiEnvMap[ENVTAG_NUMBER] = env1; 319 g_taskQueueMap[ENVTAG_NUMBER] = deque<Task *>{}; 320 // Store the mapping between the callback passed in by TS and env for subsequent calling. 321 napi_ref callFun; 322 napi_create_reference(env1, argv[0], 1, &callFun); 323 g_callBackMap[ENVTAG_NUMBER] = callFun; 324 napi_value coreID = 0; 325 { 326 std::lock_guard<std::mutex> lock_guard(envMapLock); 327 CreateArkJSContext(); 328 napi_create_uint32(env1, ENVTAG_NUMBER, &coreID); 329 ENVTAG_NUMBER++; 330 } 331 OH_LOG_ERROR(LOG_APP, "JSVM CreateJsCore END"); 332 return coreID; 333 } 334 335 // Provide an external interface for releasing the JSVM based on envId. 336 static napi_value ReleaseJsCore(napi_env env1, napi_callback_info info) { 337 OH_LOG_ERROR(LOG_APP, "JSVM ReleaseJsCore START"); 338 size_t argc = 1; 339 napi_value argv[1]; 340 napi_get_cb_info(env1, info, &argc, argv, nullptr, nullptr); 341 if (argc < 1) { 342 OH_LOG_ERROR(LOG_APP, "JSVM ReleaseJsCore the number of params must be one"); 343 return nullptr; 344 } 345 346 uint32_t coreEnvId; 347 napi_status status = napi_get_value_uint32(env1, argv[0], &coreEnvId); 348 if (status != napi_ok) { 349 OH_LOG_ERROR(LOG_APP, "JSVM CreateJsCore napi_get_value_uint32 faild"); 350 return nullptr; 351 } 352 if (g_envMap.count(coreEnvId) == 0 ) { 353 OH_LOG_ERROR(LOG_APP, "JSVM CreateJsCore not has env "); 354 return nullptr; 355 } 356 if (g_envMap[coreEnvId] != nullptr) { 357 std::lock_guard<std::mutex> lock_guard(envMapLock); 358 OH_JSVM_DestroyEnv(*g_envMap[coreEnvId]); 359 g_envMap[coreEnvId] = nullptr; 360 g_envMap.erase(coreEnvId); 361 OH_JSVM_DestroyVM(*g_vmMap[coreEnvId]); 362 g_vmMap[coreEnvId] = nullptr; 363 g_vmMap.erase(coreEnvId); 364 delete [] g_callBackStructMap[coreEnvId]; 365 g_callBackStructMap[coreEnvId] = nullptr; 366 g_callBackStructMap.erase(coreEnvId); 367 napi_delete_reference(env1, g_callBackMap[coreEnvId]); 368 g_callBackMap.erase(coreEnvId); 369 g_taskQueueMap.erase(coreEnvId); 370 } 371 OH_LOG_ERROR(LOG_APP, "JSVM ReleaseJsCore END"); 372 return nullptr; 373 } 374 375 static std::mutex mutexLock; 376 // Provide an external interface for running the JS code in the JSVM identified by a core ID. 377 static napi_value EvaluateJS(napi_env env, napi_callback_info info) { 378 OH_LOG_ERROR(LOG_APP, "JSVM EvaluateJS START"); 379 size_t argc = 2; 380 napi_value args[2] = {nullptr}; 381 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 382 uint32_t envId; 383 napi_status status = napi_get_value_uint32(env, args[0], &envId); 384 if (status != napi_ok) { 385 OH_LOG_ERROR(LOG_APP, "EvaluateJS first param should be number"); 386 return nullptr; 387 } 388 389 if (g_envMap.count(envId) == 0 || g_envMap[envId] == nullptr) { 390 OH_LOG_ERROR(LOG_APP, "EvaluateJS env is null"); 391 return nullptr; 392 } 393 std::string dataStr = napiValueToString(env, args[1]); 394 napi_value res = nullptr; 395 std::lock_guard<std::mutex> lock_guard(mutexLock); 396 { 397 // open vm scope 398 JSVM_VMScope vmscope; 399 OH_JSVM_OpenVMScope(*g_vmMap[envId], &vmscope); 400 // open env scope 401 JSVM_EnvScope envscope; 402 OH_JSVM_OpenEnvScope(*g_envMap[envId], &envscope); 403 // open handle scope 404 JSVM_HandleScope handlescope; 405 OH_JSVM_OpenHandleScope(*g_envMap[envId], &handlescope); 406 // Compile the JS script. 407 JSVM_Value sourcecodevalue; 408 OH_JSVM_CreateStringUtf8(*g_envMap[envId], dataStr.c_str(), dataStr.size(), &sourcecodevalue); 409 JSVM_Script script; 410 OH_JSVM_CompileScript(*g_envMap[envId], sourcecodevalue, nullptr, 0, true, nullptr, &script); 411 // Run the JS script. 412 JSVM_Value result; 413 OH_JSVM_RunScript(*g_envMap[envId], script, &result); 414 JSVM_ValueType type; 415 OH_JSVM_Typeof(*g_envMap[envId], result, &type); 416 OH_LOG_INFO(LOG_APP, "JSVM API TEST type: %{public}d", type); 417 // Execute tasks in the current env event queue. 418 while (!g_taskQueueMap[envId].empty()) { 419 auto task = g_taskQueueMap[envId].front(); 420 g_taskQueueMap[envId].pop_front(); 421 task->Run(); 422 delete task; 423 } 424 425 if (type == JSVM_STRING) { 426 std::string stdResult = fromOHStringValue(*g_envMap[envId], result); 427 napi_create_string_utf8(env, stdResult.c_str(), stdResult.length(), &res); 428 } else if (type == JSVM_BOOLEAN) { 429 bool ret = false; 430 std::string stdResult; 431 OH_JSVM_GetValueBool(*g_envMap[envId], result, &ret); 432 ret ? stdResult = "true" : stdResult = "false"; 433 napi_create_string_utf8(env, stdResult.c_str(), stdResult.length(), &res); 434 } else if (type == JSVM_NUMBER) { 435 int32_t num; 436 OH_JSVM_GetValueInt32(*g_envMap[envId], result, &num); 437 std::string stdResult = std::to_string(num); 438 napi_create_string_utf8(env, stdResult.c_str(), stdResult.length(), &res); 439 } else if (type == JSVM_OBJECT) { 440 JSVM_Value objResult; 441 OH_JSVM_JsonStringify(*g_envMap[envId], result, &objResult); 442 std::string stdResult = fromOHStringValue(*g_envMap[envId], objResult); 443 napi_create_string_utf8(env, stdResult.c_str(), stdResult.length(), &res); 444 } 445 bool aal = false; 446 OH_JSVM_PumpMessageLoop(*g_vmMap[envId], &aal); 447 OH_JSVM_PerformMicrotaskCheckpoint(*g_vmMap[envId]); 448 OH_JSVM_CloseHandleScope(*g_envMap[envId], handlescope); 449 OH_JSVM_CloseEnvScope(*g_envMap[envId], envscope); 450 OH_JSVM_CloseVMScope(*g_vmMap[envId], vmscope); 451 } 452 OH_LOG_ERROR(LOG_APP, "JSVM EvaluateJS END"); 453 return res; 454 } 455 ``` 456 457**Register the module.** 458 459 ```cpp 460 // create_jsvm_runtime.cpp 461 EXTERN_C_START 462 static napi_value Init(napi_env env, napi_value exports) { 463 napi_property_descriptor desc[] = { 464 {"createJsCore", nullptr, CreateJsCore, nullptr, nullptr, nullptr, napi_default, nullptr}, 465 {"releaseJsCore", nullptr, ReleaseJsCore, nullptr, nullptr, nullptr, napi_default, nullptr}, 466 {"evaluateJS", nullptr, EvaluateJS, nullptr, nullptr, nullptr, napi_default, nullptr} 467 }; 468 469 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 470 return exports; 471 } 472 EXTERN_C_END 473 474 static napi_module demoModule = { 475 .nm_version = 1, 476 .nm_flags = 0, 477 .nm_filename = nullptr, 478 .nm_register_func = Init, 479 .nm_modname = "entry", 480 .nm_priv = ((void *)0), 481 .reserved = {0}, 482 }; 483 484 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); } 485 ``` 486 487 3. Run ArkTS code. 488 489 ```ts 490 import { hilog } from '@kit.PerformanceAnalysisKit'; 491 import testNapi from 'libentry.so'; 492 493 function MyCallback(a:string, b:string):string { 494 console.log("TEST MyCallback run: " + a); 495 b = "callback done"; 496 console.log("TEST MyCallback run: " + b); 497 return "callback pass"; 498 } 499 500 function MyCallback2(a:string, b:string):string { 501 console.log("TEST MyCallback2 start: a = " + a); 502 console.log("TEST MyCallback2 start: b = " + b); 503 return "MyCallback2 pass"; 504 } 505 506 @Entry 507 @Component 508 struct Index { 509 @State message: string = 'Hello World'; 510 511 build() { 512 Row() { 513 Column() { 514 Text(this.message) 515 .fontSize(50) 516 .fontWeight(FontWeight.Bold) 517 .onClick(() => { 518 let sourcecodestr = `{ 519 let a = "hello World"; 520 consoleinfo(a); 521 const mPromise = createPromise(); 522 mPromise.then((result) => { 523 assertEqual(result, 0); 524 onJSResultCallback(result, "abc", "v"); 525 }); 526 a; 527 };`; 528 529 let sourcecodestr1 = `{ 530 let a = "second hello"; 531 consoleinfo(a); 532 let b = add(99, 1); 533 assertEqual(100, b); 534 assertEqual(add(99, 1), 100); 535 createPromise().then((result) => { 536 assertEqual(result, 1); 537 consoleinfo(onJSResultCallback(result, '999','666')); 538 }); 539 a; 540 };`; 541 542 // Create the first VM and bind the TS callback. 543 const coreId = testNapi.createJsCore(MyCallback); 544 console.log("TEST coreId: " + coreId); 545 // Run JS code in the first VM. 546 console.log("TEST evaluateJS : " + testNapi.evaluateJS(coreId, sourcecodestr)); 547 548 // Create the second VM and bind the TS callback. 549 const coreId1 = testNapi.createJsCore(MyCallback2); 550 console.log("TEST coreId: " + coreId1); 551 // Run JS code in the second VM. 552 console.log("TEST evaluateJS : " + testNapi.evaluateJS(coreId1, sourcecodestr1)); 553 554 // Release the first VM. 555 testNapi.releaseJsCore(coreId); 556 // Release the second VM. 557 testNapi.releaseJsCore(coreId1); 558 hilog.info(0x0000, 'testTag', 'Test NAPI end'); 559 }) 560 } 561 .width('100%') 562 } 563 .height('100%') 564 } 565 } 566 ``` 567