1e41f4b71Sopenharmony_ci# JSVM-API使用规范 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci## 生命周期管理 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci**【规则】** 合理使用`OH_JSVM_OpenHandleScope`和`OH_JSVM_CloseHandleScope`管理JSVM_Value的生命周期,做到生命周期最小化,避免发生内存泄漏问题。 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ci每个JSVM_Value属于特定的HandleScope,HandleScope通过`OH_JSVM_OpenHandleScope`和`OH_JSVM_CloseHandleScope`来建立和关闭,HandleScope关闭后,所属的JSVM_Value就会自动释放。 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci**注意事项**: 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ci1. JSVM_Value必须在HandleScope打开后才可创建(Node-API无该限制),否则会造成应用崩溃; 12e41f4b71Sopenharmony_ci2. JSVM_Value不能在其对应的HandleScope关闭后使用,如需持久化持有,需调用`OH_JSVM_CreateReference`转化为`JSVM_Ref`; 13e41f4b71Sopenharmony_ci3. Scope(包括JSVM_VMScope、JSVM_EnvScope、JSVM_HandleScope)需逆序关闭,最先打开的Scope需最后关闭,否则可能造成应用崩溃; 14e41f4b71Sopenharmony_ci 15e41f4b71Sopenharmony_ci**Scope关闭错误示例** 16e41f4b71Sopenharmony_ci``` 17e41f4b71Sopenharmony_ci// 未逆序关闭JSVM_VMScope,可能造成应用崩溃 18e41f4b71Sopenharmony_ciJSVM_VM vm; 19e41f4b71Sopenharmony_ciJSVM_CreateVMOptions options; 20e41f4b71Sopenharmony_ciOH_JSVM_CreateVM(&options, &vm); 21e41f4b71Sopenharmony_ci 22e41f4b71Sopenharmony_ciJSVM_VMScope vmScope1, vmScope2; 23e41f4b71Sopenharmony_ciOH_JSVM_OpenVMScope(vm, &vmScope1); 24e41f4b71Sopenharmony_ciOH_JSVM_OpenVMScope(vm, &vmScope2); 25e41f4b71Sopenharmony_ci 26e41f4b71Sopenharmony_ci// 正确顺序为先关闭vmScope2,再关闭vmScope1 27e41f4b71Sopenharmony_ciOH_JSVM_CloseVMScope(vm, vmScope1); 28e41f4b71Sopenharmony_ciOH_JSVM_CloseVMScope(vm, vmScope2); 29e41f4b71Sopenharmony_ciOH_JSVM_DestroyVM(vm); 30e41f4b71Sopenharmony_ci``` 31e41f4b71Sopenharmony_ci 32e41f4b71Sopenharmony_ci 33e41f4b71Sopenharmony_ci**C++使用封装** 34e41f4b71Sopenharmony_ci 35e41f4b71Sopenharmony_ci``` 36e41f4b71Sopenharmony_ciclass HandleScopeWrapper { 37e41f4b71Sopenharmony_ci public: 38e41f4b71Sopenharmony_ci HandleScopeWrapper(JSVM_Env env) : env(env) { 39e41f4b71Sopenharmony_ci OH_JSVM_OpenHandleScope(env, &handleScope); 40e41f4b71Sopenharmony_ci } 41e41f4b71Sopenharmony_ci 42e41f4b71Sopenharmony_ci ~HandleScopeWrapper() { 43e41f4b71Sopenharmony_ci OH_JSVM_CloseHandleScope(env, handleScope); 44e41f4b71Sopenharmony_ci } 45e41f4b71Sopenharmony_ci 46e41f4b71Sopenharmony_ci HandleScopeWrapper(const HandleScopeWrapper&) = delete; 47e41f4b71Sopenharmony_ci HandleScopeWrapper& operator=(const HandleScopeWrapper&) = delete; 48e41f4b71Sopenharmony_ci HandleScopeWrapper(HandleScopeWrapper&&) = delete; 49e41f4b71Sopenharmony_ci void* operator new(size_t) = delete; 50e41f4b71Sopenharmony_ci void* operator new[](size_t) = delete; 51e41f4b71Sopenharmony_ci 52e41f4b71Sopenharmony_ci protected: 53e41f4b71Sopenharmony_ci JSVM_Env env; 54e41f4b71Sopenharmony_ci JSVM_HandleScope handleScope; 55e41f4b71Sopenharmony_ci}; 56e41f4b71Sopenharmony_ci``` 57e41f4b71Sopenharmony_ci 58e41f4b71Sopenharmony_ci**示例**: 59e41f4b71Sopenharmony_ci 60e41f4b71Sopenharmony_ci```c++ 61e41f4b71Sopenharmony_ci// 在for循环中频繁调用JSVM接口创建js对象时,要加handle_scope及时释放不再使用的资源。 62e41f4b71Sopenharmony_ci// 下面例子中,每次循环结束局部变量res的生命周期已结束,因此加scope及时释放其持有的js对象,防止内存泄漏 63e41f4b71Sopenharmony_ci// 每次for循环结束后,触发HandleScopeWrapper的析构函数,释放scope持有的js对象 64e41f4b71Sopenharmony_cifor (int i = 0; i < 100000; i++) 65e41f4b71Sopenharmony_ci{ 66e41f4b71Sopenharmony_ci HandleScopeWrapper scope(env); 67e41f4b71Sopenharmony_ci JSVM_Value res; 68e41f4b71Sopenharmony_ci OH_JSVM_CreateObject(env, &res); 69e41f4b71Sopenharmony_ci if (i == 1000) { 70e41f4b71Sopenharmony_ci // break退出循环后会自动调用HandleScopeWrapper析构函数释放资源 71e41f4b71Sopenharmony_ci break; 72e41f4b71Sopenharmony_ci } 73e41f4b71Sopenharmony_ci} 74e41f4b71Sopenharmony_ci``` 75e41f4b71Sopenharmony_ci 76e41f4b71Sopenharmony_ci## 多引擎实例上下文敏感 77e41f4b71Sopenharmony_ci 78e41f4b71Sopenharmony_ci**【规则】** 多引擎实例(VM)场景下,禁止通过JSVM-API跨引擎实例访问JS对象。 79e41f4b71Sopenharmony_ci 80e41f4b71Sopenharmony_ci引擎实例是一个独立运行环境,JS对象创建访问等操作必须在同一个引擎实例中进行。若在不同引擎实例中操作同一个对象,可能会引发程序崩溃。引擎实例在接口中体现为JSVM_Env。 81e41f4b71Sopenharmony_ci 82e41f4b71Sopenharmony_ci**错误示例**: 83e41f4b71Sopenharmony_ci 84e41f4b71Sopenharmony_ci```c++ 85e41f4b71Sopenharmony_ci// 线程1执行,在env1创建string对象,值为"bar"、 86e41f4b71Sopenharmony_ciOH_JSVM_CreateStringUtf8(env1, "value1", JSVM_AUTO_LENGTH , &string); 87e41f4b71Sopenharmony_ci// 线程2执行,在env2创建object对象,并将上述的string对象设置到object对象中 88e41f4b71Sopenharmony_ciJSVM_Status status = OH_JSVM_CreateObject(env2, &object); 89e41f4b71Sopenharmony_ciif (status != JSVM_OK) 90e41f4b71Sopenharmony_ci{ 91e41f4b71Sopenharmony_ci return; 92e41f4b71Sopenharmony_ci} 93e41f4b71Sopenharmony_ci 94e41f4b71Sopenharmony_cistatus = OH_JSVM_SetNamedProperty(env2, object, "string1", string); 95e41f4b71Sopenharmony_ciif (status != JSVM_OK) 96e41f4b71Sopenharmony_ci{ 97e41f4b71Sopenharmony_ci return; 98e41f4b71Sopenharmony_ci} 99e41f4b71Sopenharmony_ci``` 100e41f4b71Sopenharmony_ci 101e41f4b71Sopenharmony_ci所有的JS对象都隶属于具体的某一JSVM_Env,不可将env1的对象,设置到env2中的对象中。在env2中一旦访问到env1的对象,程序可能会发生崩溃。 102e41f4b71Sopenharmony_ci 103e41f4b71Sopenharmony_ci## 多线程共享引擎实例 104e41f4b71Sopenharmony_ci 105e41f4b71Sopenharmony_ci【规则】多线程同时使用同一个引擎实例的场景下,需要加锁使用。保证一个引擎实例在同一时刻只能在一个线程执行。多线程同一时刻同时使用引擎实例可能造成应用崩溃。 106e41f4b71Sopenharmony_ci 107e41f4b71Sopenharmony_ci**注意事项**: 108e41f4b71Sopenharmony_ci 109e41f4b71Sopenharmony_ci1. `OH_JSVM_IsLocked`的结果为**当前线程**是否持有引擎实例的锁,无需设置循环等待其他线程释放锁; 110e41f4b71Sopenharmony_ci2. `OH_JSVM_AcquireLock`在同一线程中嵌套使用不会造成死锁; 111e41f4b71Sopenharmony_ci3. 使用`OH_JSVM_ReleaseLock`时需判断是否在最外层,避免同一线程中嵌套使用`OH_JSVM_AcquireLock`的场景下内层释放了整个线程的锁; 112e41f4b71Sopenharmony_ci4. `OH_JSVM_AcquireLock`后需调用`OH_JSVM_OpenHandleScope`让引擎实例进入线程;`OH_JSVM_ReleaseLock`后需调用`OH_JSVM_ReleaseLock`让引擎实例退出线程; 113e41f4b71Sopenharmony_ci5. 不同线程禁止嵌套使用引擎实例,如需临时切换线程使用引擎实例,请确保`JSVM_Value`已保存为`JSVM_Ref`,释放锁后对`JSVM_Value`将不可访问; 114e41f4b71Sopenharmony_ci6. 需注意资源获取的顺序为:锁 -> VMScope -> EnvScope -> HandleScope,释放资源的顺序正好相反,错误的顺序可能导致程序崩溃; 115e41f4b71Sopenharmony_ci 116e41f4b71Sopenharmony_ci**C++使用封装**: 117e41f4b71Sopenharmony_ci 118e41f4b71Sopenharmony_ci``` 119e41f4b71Sopenharmony_ciclass LockWrapper { 120e41f4b71Sopenharmony_ci public: 121e41f4b71Sopenharmony_ci // 构造函数,获取锁、VMScope、EnvScope 122e41f4b71Sopenharmony_ci LockWrapper(JSVM_Env env) : env(env) { 123e41f4b71Sopenharmony_ci OH_JSVM_IsLocked(env, &isLocked); 124e41f4b71Sopenharmony_ci if (!isLocked) { 125e41f4b71Sopenharmony_ci OH_JSVM_AcquireLock(env); 126e41f4b71Sopenharmony_ci OH_JSVM_GetVM(env, &vm); 127e41f4b71Sopenharmony_ci OH_JSVM_OpenVMScope(vm, &vmScope); 128e41f4b71Sopenharmony_ci OH_JSVM_OpenEnvScope(env, &envScope); 129e41f4b71Sopenharmony_ci } 130e41f4b71Sopenharmony_ci } 131e41f4b71Sopenharmony_ci 132e41f4b71Sopenharmony_ci // 析构函数,释放EnvScope、VMScope、锁 133e41f4b71Sopenharmony_ci ~LockWrapper() { 134e41f4b71Sopenharmony_ci if (!isLocked) { 135e41f4b71Sopenharmony_ci OH_JSVM_CloseEnvScope(env, envScope); 136e41f4b71Sopenharmony_ci OH_JSVM_CloseVMScope(vm, vmScope); 137e41f4b71Sopenharmony_ci OH_JSVM_ReleaseLock(env); 138e41f4b71Sopenharmony_ci } 139e41f4b71Sopenharmony_ci } 140e41f4b71Sopenharmony_ci 141e41f4b71Sopenharmony_ci LockWrapper(const LockWrapper&) = delete; 142e41f4b71Sopenharmony_ci LockWrapper& operator=(const LockWrapper&) = delete; 143e41f4b71Sopenharmony_ci LockWrapper(LockWrapper&&) = delete; 144e41f4b71Sopenharmony_ci void* operator new(size_t) = delete; 145e41f4b71Sopenharmony_ci void* operator new[](size_t) = delete; 146e41f4b71Sopenharmony_ci 147e41f4b71Sopenharmony_ci private: 148e41f4b71Sopenharmony_ci JSVM_Env env; 149e41f4b71Sopenharmony_ci JSVM_EnvScope envScope; 150e41f4b71Sopenharmony_ci JSVM_VMScope vmScope; 151e41f4b71Sopenharmony_ci JSVM_VM vm; 152e41f4b71Sopenharmony_ci bool isLocked; 153e41f4b71Sopenharmony_ci}; 154e41f4b71Sopenharmony_ci``` 155e41f4b71Sopenharmony_ci 156e41f4b71Sopenharmony_ci 157e41f4b71Sopenharmony_ci 158e41f4b71Sopenharmony_ci**正确示例**: 159e41f4b71Sopenharmony_ci 160e41f4b71Sopenharmony_ci``` 161e41f4b71Sopenharmony_ci// 该用例演示了多线程中使用vm 162e41f4b71Sopenharmony_ci// t1线程先获取锁,并继续JSVM-API的调用 163e41f4b71Sopenharmony_ci// t2线程会在获取锁处阻塞,直到t1线程执行结束释放锁后,t2线程继续执行,调用JSVM-API接口 164e41f4b71Sopenharmony_cistatic napi_value Add([[maybe_unused]] napi_env _env, [[maybe_unused]] napi_callback_info _info) { 165e41f4b71Sopenharmony_ci static JSVM_VM vm; 166e41f4b71Sopenharmony_ci static JSVM_Env env; 167e41f4b71Sopenharmony_ci if (aa == 0) { 168e41f4b71Sopenharmony_ci OH_JSVM_Init(nullptr); 169e41f4b71Sopenharmony_ci aa++; 170e41f4b71Sopenharmony_ci // create vm 171e41f4b71Sopenharmony_ci JSVM_CreateVMOptions options; 172e41f4b71Sopenharmony_ci memset(&options, 0, sizeof(options)); 173e41f4b71Sopenharmony_ci OH_JSVM_CreateVM(&options, &vm); 174e41f4b71Sopenharmony_ci // create env 175e41f4b71Sopenharmony_ci OH_JSVM_CreateEnv(vm, 0, nullptr, &env); 176e41f4b71Sopenharmony_ci } 177e41f4b71Sopenharmony_ci 178e41f4b71Sopenharmony_ci std::thread t1([]() { 179e41f4b71Sopenharmony_ci LockWrapper lock(env); 180e41f4b71Sopenharmony_ci JSVM_HandleScope handleScope; 181e41f4b71Sopenharmony_ci OH_JSVM_OpenHandleScope(env, &handleScope); 182e41f4b71Sopenharmony_ci JSVM_Value value; 183e41f4b71Sopenharmony_ci JSVM_Status rst = OH_JSVM_CreateInt32(env, 32, &value); // 32: numerical value 184e41f4b71Sopenharmony_ci if (rst == JSVM_OK) { 185e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM:t1 OH_JSVM_CreateInt32 suc"); 186e41f4b71Sopenharmony_ci } else { 187e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM:t1 OH_JSVM_CreateInt32 fail"); 188e41f4b71Sopenharmony_ci } 189e41f4b71Sopenharmony_ci int32_t num1; 190e41f4b71Sopenharmony_ci OH_JSVM_GetValueInt32(env, value, &num1); 191e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM:t1 num1 = %{public}d", num1); 192e41f4b71Sopenharmony_ci OH_JSVM_CloseHandleScope(env, handleScope); 193e41f4b71Sopenharmony_ci }); 194e41f4b71Sopenharmony_ci std::thread t2([]() { 195e41f4b71Sopenharmony_ci LockWrapper lock(env); 196e41f4b71Sopenharmony_ci JSVM_HandleScope handleScope; 197e41f4b71Sopenharmony_ci OH_JSVM_OpenHandleScope(env, &handleScope); 198e41f4b71Sopenharmony_ci JSVM_Value value; 199e41f4b71Sopenharmony_ci JSVM_Status rst = OH_JSVM_CreateInt32(env, 32, &value); // 32: numerical value 200e41f4b71Sopenharmony_ci if (rst == JSVM_OK) { 201e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM:t2 OH_JSVM_CreateInt32 suc"); 202e41f4b71Sopenharmony_ci } else { 203e41f4b71Sopenharmony_ci OH_LOG_ERROR(LOG_APP, "JSVM:t2 OH_JSVM_CreateInt32 fail"); 204e41f4b71Sopenharmony_ci } 205e41f4b71Sopenharmony_ci int32_t num1; 206e41f4b71Sopenharmony_ci OH_JSVM_GetValueInt32(env, value, &num1); 207e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM:t2 num1 = %{public}d", num1); 208e41f4b71Sopenharmony_ci OH_JSVM_CloseHandleScope(env, handleScope); 209e41f4b71Sopenharmony_ci }); 210e41f4b71Sopenharmony_ci t1.detach(); 211e41f4b71Sopenharmony_ci t2.detach(); 212e41f4b71Sopenharmony_ci return nullptr; 213e41f4b71Sopenharmony_ci} 214e41f4b71Sopenharmony_ci``` 215e41f4b71Sopenharmony_ci 216e41f4b71Sopenharmony_ci## 获取JS传入参数及其数量 217e41f4b71Sopenharmony_ci 218e41f4b71Sopenharmony_ci**【规则】** 当传入OH_JSVM_GetCbInfo的argv不为nullptr时,argv的长度必须大于等于传入argc声明的大小。 219e41f4b71Sopenharmony_ci 220e41f4b71Sopenharmony_ci当argv不为nullptr时,OH_JSVM_GetCbInfo会根据argc声明的数量将JS实际传入的参数写入argv。如果argc小于等于实际JS传入参数的数量,该接口仅会将声明的argc数量的参数写入argv;而当argc大于实际参数数量时,该接口会在argv的尾部填充undefined。 221e41f4b71Sopenharmony_ci 222e41f4b71Sopenharmony_ci**错误示例** 223e41f4b71Sopenharmony_ci 224e41f4b71Sopenharmony_ci```cpp 225e41f4b71Sopenharmony_cistatic JSVM_Value IncorrectDemo1(JSVM_Env env, JSVM_CallbackInfo info) { 226e41f4b71Sopenharmony_ci // argc 未正确的初始化,其值为不确定的随机值,导致 argv 的长度可能小于 argc 声明的数量,数据越界。 227e41f4b71Sopenharmony_ci size_t argc; 228e41f4b71Sopenharmony_ci JSVM_Value argv[10] = {nullptr}; 229e41f4b71Sopenharmony_ci OH_JSVM_GetCbInfo(env, info, &argc, argv, nullptr, nullptr); 230e41f4b71Sopenharmony_ci return nullptr; 231e41f4b71Sopenharmony_ci} 232e41f4b71Sopenharmony_ci 233e41f4b71Sopenharmony_cistatic JSVM_Value IncorrectDemo2(JSVM_Env env, JSVM_CallbackInfo info) { 234e41f4b71Sopenharmony_ci // argc 声明的数量大于 argv 实际初始化的长度,导致 OH_JSVM_GetCbInfo 接口在写入 argv 时数据越界。 235e41f4b71Sopenharmony_ci size_t argc = 5; 236e41f4b71Sopenharmony_ci JSVM_Value argv[3] = {nullptr}; 237e41f4b71Sopenharmony_ci OH_JSVM_GetCbInfo(env, info, &argc, argv, nullptr, nullptr); 238e41f4b71Sopenharmony_ci return nullptr; 239e41f4b71Sopenharmony_ci} 240e41f4b71Sopenharmony_ci``` 241e41f4b71Sopenharmony_ci 242e41f4b71Sopenharmony_ci**正确示例** 243e41f4b71Sopenharmony_ci 244e41f4b71Sopenharmony_ci```cpp 245e41f4b71Sopenharmony_cistatic JSVM_Value GetArgvDemo1(napi_env env, JSVM_CallbackInfo info) { 246e41f4b71Sopenharmony_ci size_t argc = 0; 247e41f4b71Sopenharmony_ci // argv 传入 nullptr 来获取传入参数真实数量 248e41f4b71Sopenharmony_ci OH_JSVM_GetCbInfo(env, info, &argc, nullptr, nullptr, nullptr); 249e41f4b71Sopenharmony_ci // JS 传入参数为0,不执行后续逻辑 250e41f4b71Sopenharmony_ci if (argc == 0) { 251e41f4b71Sopenharmony_ci return nullptr; 252e41f4b71Sopenharmony_ci } 253e41f4b71Sopenharmony_ci // 创建数组用以获取JS传入的参数 254e41f4b71Sopenharmony_ci JSVM_Value* argv = new JSVM_Value[argc]; 255e41f4b71Sopenharmony_ci OH_JSVM_GetCbInfo(env, info, &argc, argv, nullptr, nullptr); 256e41f4b71Sopenharmony_ci // 业务代码 257e41f4b71Sopenharmony_ci // ... ... 258e41f4b71Sopenharmony_ci // argv 为 new 创建的对象,在使用完成后手动释放 259e41f4b71Sopenharmony_ci delete argv; 260e41f4b71Sopenharmony_ci return nullptr; 261e41f4b71Sopenharmony_ci} 262e41f4b71Sopenharmony_ci 263e41f4b71Sopenharmony_cistatic JSVM_Value GetArgvDemo2(napi_env env, JSVM_CallbackInfo info) { 264e41f4b71Sopenharmony_ci size_t argc = 2; 265e41f4b71Sopenharmony_ci JSVM_Value* argv[2] = {nullptr}; 266e41f4b71Sopenharmony_ci // OH_JSVM_GetCbInfo 会向 argv 中写入 argc 个 JS 传入参数或 undefined 267e41f4b71Sopenharmony_ci OH_JSVM_GetCbInfo(env, info, &argc, nullptr, nullptr, nullptr); 268e41f4b71Sopenharmony_ci // 业务代码 269e41f4b71Sopenharmony_ci // ... ... 270e41f4b71Sopenharmony_ci return nullptr; 271e41f4b71Sopenharmony_ci} 272e41f4b71Sopenharmony_ci``` 273e41f4b71Sopenharmony_ci 274e41f4b71Sopenharmony_ci## 异常处理 275e41f4b71Sopenharmony_ci 276e41f4b71Sopenharmony_ci**【建议】** JSVM-API接口调用发生异常需要及时处理,不能遗漏异常到后续逻辑,否则程序可能发生不可预期行为。 277e41f4b71Sopenharmony_ci 278e41f4b71Sopenharmony_ci 根据主从类型,异常处理可以分为两类: 279e41f4b71Sopenharmony_ci 280e41f4b71Sopenharmony_ci1. 回调函数(JS主,Native从)中Native发生异常,需往JSVM中抛出异常 281e41f4b71Sopenharmony_ci ```c++ 282e41f4b71Sopenharmony_ci // Native主,JSVM从 283e41f4b71Sopenharmony_ci void ThrowError() { 284e41f4b71Sopenharmony_ci bool isPending = false; 285e41f4b71Sopenharmony_ci if (JSVM_OK == OH_JSVM_IsExceptionPending((env), &isPending) && isPending) { 286e41f4b71Sopenharmony_ci JSVM_Value error; 287e41f4b71Sopenharmony_ci // 获取并清空JSVM异常 288e41f4b71Sopenharmony_ci if (JSVM_OK == OH_JSVM_GetAndClearLastException((env), &error)) { 289e41f4b71Sopenharmony_ci // 获取异常堆栈 290e41f4b71Sopenharmony_ci JSVM_Value stack = nullptr; 291e41f4b71Sopenharmony_ci CALL_JSVM(env, OH_JSVM_GetNamedProperty((env), error, "stack", &stack)); 292e41f4b71Sopenharmony_ci 293e41f4b71Sopenharmony_ci JSVM_Value message = nullptr; 294e41f4b71Sopenharmony_ci CALL_JSVM(env, OH_JSVM_GetNamedProperty((env), error, "message", &message)); 295e41f4b71Sopenharmony_ci 296e41f4b71Sopenharmony_ci // 需实现将JS字符串转化为C++的std::string 297e41f4b71Sopenharmony_ci std::string stackstr = stack? GetValueString(stack) : ""; 298e41f4b71Sopenharmony_ci std::string messagestr = message? GetValueString(message) : ""; 299e41f4b71Sopenharmony_ci // 抛出异常,需实现JSError 300e41f4b71Sopenharmony_ci throw JSError(*this, messagestr, stackstr); 301e41f4b71Sopenharmony_ci } 302e41f4b71Sopenharmony_ci } 303e41f4b71Sopenharmony_ci // 抛出异常,需实现JSError 304e41f4b71Sopenharmony_ci throw JSError(*this, "JSVM Runtime: unkown execption"); 305e41f4b71Sopenharmony_ci } 306e41f4b71Sopenharmony_ci 307e41f4b71Sopenharmony_ci status = OH_JSVM_SetNamedProperty(env, object, "foo", string); 308e41f4b71Sopenharmony_ci // JSVM-API调用失败,清空JS引擎实例pending的异常,抛出C++异常 309e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 310e41f4b71Sopenharmony_ci ThrowError(); 311e41f4b71Sopenharmony_ci } 312e41f4b71Sopenharmony_ci ``` 313e41f4b71Sopenharmony_ci 314e41f4b71Sopenharmony_ci2. C++调用JSVM-API(Native主,JS从)失败,需清理JSVM中等待处理的异常,避免影响后续JSVM-API的执行,并设置C++异常处理分支(或抛出C++异常) 315e41f4b71Sopenharmony_ci ``` 316e41f4b71Sopenharmony_ci // JSVM主, Native从 317e41f4b71Sopenharmony_ci void DoSomething() { 318e41f4b71Sopenharmony_ci throw("Do something failed"); 319e41f4b71Sopenharmony_ci } 320e41f4b71Sopenharmony_ci 321e41f4b71Sopenharmony_ci // Demo1: 捕获到C++异常,抛出异常到JSVM中 322e41f4b71Sopenharmony_ci JSVM_Value NativeFunctionExceptionDemo1(JSVM_Env env, JSVM_CallbackInfo info) { 323e41f4b71Sopenharmony_ci try { 324e41f4b71Sopenharmony_ci DoSomething(); 325e41f4b71Sopenharmony_ci } catch (const char *ex) { 326e41f4b71Sopenharmony_ci OH_JSVM_ThrowError(env, nullptr, ex); 327e41f4b71Sopenharmony_ci return nullptr; 328e41f4b71Sopenharmony_ci } 329e41f4b71Sopenharmony_ci return nullptr; 330e41f4b71Sopenharmony_ci } 331e41f4b71Sopenharmony_ci 332e41f4b71Sopenharmony_ci // Demo2: JSVM-API调用失败,抛出异常到JSVM中 333e41f4b71Sopenharmony_ci JSVM_Value NativeFunctionExceptionDemo2(JSVM_Env env, JSVM_CallbackInfo info) { 334e41f4b71Sopenharmony_ci JSVM_Value JSBool = nullptr; 335e41f4b71Sopenharmony_ci bool value = false; 336e41f4b71Sopenharmony_ci auto status = OH_JSVM_GetValueBool(env, JSBool, &value); 337e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 338e41f4b71Sopenharmony_ci OH_JSVM_ThrowError(env, nullptr, "Get bool value failed"); 339e41f4b71Sopenharmony_ci return nullptr; 340e41f4b71Sopenharmony_ci } 341e41f4b71Sopenharmony_ci return nullptr; 342e41f4b71Sopenharmony_ci } 343e41f4b71Sopenharmony_ci 344e41f4b71Sopenharmony_ci // Demo3:JSVM-API调用失败且在调用过程中已向JSVM中添加等待处理的异常,则无需再向JSVM中抛出异常 345e41f4b71Sopenharmony_ci JSVM_Value NativeFunctionExceptionDemo3(JSVM_Env env, JSVM_CallbackInfo info) { 346e41f4b71Sopenharmony_ci std::string sourcecodestr = R"JS( 347e41f4b71Sopenharmony_ci throw Error('Error throw from js'); 348e41f4b71Sopenharmony_ci )JS"; 349e41f4b71Sopenharmony_ci JSVM_Value sourcecodevalue = nullptr; 350e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, sourcecodestr.c_str(), sourcecodestr.size(), &sourcecodevalue); 351e41f4b71Sopenharmony_ci JSVM_Script script; 352e41f4b71Sopenharmony_ci auto status = OH_JSVM_CompileScript(env, sourcecodevalue, nullptr, 0, true, nullptr, &script); 353e41f4b71Sopenharmony_ci JSVM_Value result; 354e41f4b71Sopenharmony_ci // 执行JS脚本,执行过程中抛出JS异常 355e41f4b71Sopenharmony_ci status = OH_JSVM_RunScript(env, script, &result); 356e41f4b71Sopenharmony_ci if (status != JSVM_OK) { 357e41f4b71Sopenharmony_ci bool isPending = false; 358e41f4b71Sopenharmony_ci // 如果已有异常,则无需再向JSVM中抛出异常; 359e41f4b71Sopenharmony_ci // 如需处理并抛出新异常,需先处理JSVM中等待的异常 360e41f4b71Sopenharmony_ci if (JSVM_OK == OH_JSVM_IsExceptionPending((env), &isPending) && isPending) { 361e41f4b71Sopenharmony_ci return nullptr; 362e41f4b71Sopenharmony_ci } 363e41f4b71Sopenharmony_ci OH_JSVM_ThrowError(env, nullptr, "Runscript failed"); 364e41f4b71Sopenharmony_ci return nullptr; 365e41f4b71Sopenharmony_ci } 366e41f4b71Sopenharmony_ci return nullptr; 367e41f4b71Sopenharmony_ci } 368e41f4b71Sopenharmony_ci 369e41f4b71Sopenharmony_ci // 绑定NativeFunction到JSVM中,省略 370e41f4b71Sopenharmony_ci std::string sourcecodestr = R"JS( 371e41f4b71Sopenharmony_ci // consolelog需用户实现 372e41f4b71Sopenharmony_ci try { 373e41f4b71Sopenharmony_ci // 调用Native函数 374e41f4b71Sopenharmony_ci NativeFunction() 375e41f4b71Sopenharmony_ci } catch (e) { 376e41f4b71Sopenharmony_ci // 处理Native中产生的异常 377e41f4b71Sopenharmony_ci consolelog(e.message) 378e41f4b71Sopenharmony_ci } 379e41f4b71Sopenharmony_ci )JS"; 380e41f4b71Sopenharmony_ci JSVM_Value sourcecodevalue = nullptr; 381e41f4b71Sopenharmony_ci OH_JSVM_CreateStringUtf8(env, sourcecodestr.c_str(), sourcecodestr.size(), &sourcecodevalue); 382e41f4b71Sopenharmony_ci JSVM_Script script; 383e41f4b71Sopenharmony_ci auto status = OH_JSVM_CompileScript(env, sourcecodevalue, nullptr, 0, true, nullptr, &script); 384e41f4b71Sopenharmony_ci OH_LOG_INFO(LOG_APP, "JSVM API TEST: %{public}d", (uint32_t)status); 385e41f4b71Sopenharmony_ci JSVM_Value result; 386e41f4b71Sopenharmony_ci // 执行JS脚本,JS调用Native方法 387e41f4b71Sopenharmony_ci status = OH_JSVM_RunScript(env, script, &result); 388e41f4b71Sopenharmony_ci ``` 389e41f4b71Sopenharmony_ci 390e41f4b71Sopenharmony_ci**注意事项**:回调函数中调用JSVM-API失败,如要向JSVM中抛异常,需保证JSVM中无等待处理的异常,也可以不抛出异常,JS的try-catch块可以捕获回调函数调用API失败产生的JS异常,见`NativeFunctionExceptionDemo3`。 391e41f4b71Sopenharmony_ci 392e41f4b71Sopenharmony_ci## 上下文绑定对象 393e41f4b71Sopenharmony_ci 394e41f4b71Sopenharmony_ci**【规则】**:调用JSVM-API生成的JS函数、对象需绑定到上下文中才能从JS侧访问,`OH_JSVM_CreateFunction`接口中的`const char *`参数为创建函数的属性`name`,不代表上下文中指向该函数的函数名。调用JSVM-API生成的类、对象同理。 395e41f4b71Sopenharmony_ci 396e41f4b71Sopenharmony_ci**示例** 397e41f4b71Sopenharmony_ci 398e41f4b71Sopenharmony_ci``` 399e41f4b71Sopenharmony_ciJSVM_Value JSFunc = nullptr; 400e41f4b71Sopenharmony_ciconst char *name = "NativeFunction"; 401e41f4b71Sopenharmony_ciJSVM_CallbackStruct cb = {NativeFunction, nullptr}; 402e41f4b71Sopenharmony_ci// 创建JS函数,该函数的属性 "name" 为 "NativeFunction" 403e41f4b71Sopenharmony_ciOH_JSVM_CreateFunction(env, name, strlen(name), &cb, &JSFunc); 404e41f4b71Sopenharmony_ci// 绑定函数到上下文 405e41f4b71Sopenharmony_ci// 获取上下文的global对象 406e41f4b71Sopenharmony_ciJSVM_Value global = nullptr; 407e41f4b71Sopenharmony_ciOH_JSVM_GetGlobal(env, &global); 408e41f4b71Sopenharmony_ci// 创建JS字符串"FunctionNameInJSContext" 409e41f4b71Sopenharmony_ciJSVM_Value key = nullptr; 410e41f4b71Sopenharmony_ciOH_JSVM_CreateStringLatin1(env, "FunctionNameInJSContext", JSVM_AUTO_LENGTH, &key); 411e41f4b71Sopenharmony_ci// 设置global的属性"FunctionNameInJSContext"为JSFunc,将函数绑定到上下文中 412e41f4b71Sopenharmony_ciOH_JSVM_SetProperty(env, global, key, JSFunc); 413e41f4b71Sopenharmony_ci// 在JS中调用函数 414e41f4b71Sopenharmony_cistd::string sourcecodestr = R"JS( 415e41f4b71Sopenharmony_ci // consolelog需用户实现 416e41f4b71Sopenharmony_ci FunctionNameInJSContext() // 调用成功 417e41f4b71Sopenharmony_ci consolelog(FunctionNameInJSContext.name) // 打印 "NativeFunction" 418e41f4b71Sopenharmony_ci try { 419e41f4b71Sopenharmony_ci NativeFunction() // 无法找到该函数,抛出异常 420e41f4b71Sopenharmony_ci } catch (e) { 421e41f4b71Sopenharmony_ci consolelog(e.message) 422e41f4b71Sopenharmony_ci } 423e41f4b71Sopenharmony_ci)JS"; 424e41f4b71Sopenharmony_ci```