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```