• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用JSVM-API进行异常的定制化处理
2<!--Kit: NDK Development-->
3<!--Subsystem: arkcompiler-->
4<!--Owner: @yuanxiaogou; @string_sz-->
5<!--Designer: @knightaoko-->
6<!--Tester: @test_lzz-->
7<!--Adviser: @fang-jinxu-->
8
9## 简介
10
11JSVM-API提供了一组用于处理JSVM异常的接口。通过这些接口,可以向JSVM注册回调函数。当JSVM触发异常时,会调用已注册的回调函数。
12这些接口提供对JS引擎错误的定制化处理,帮助开发者管理运行时错误和异常。
13
14## 基本概念
15
16当JS引擎遇到内存不足的问题时,系统会抛出一个OOM Error,如果开发者提前向JS引擎中注册了OOM Error的处理函数,系统就会调用这个设置的处理函数,开发者可以在处理函数中执行一些清理或者日志记录操作。
17当JS引擎发生致命错误,例如执行JavaScript代码时出现无法恢复的错误,系统会抛出一个Fatal Error,并调用用户预先设置的处理函数。在该处理函数中,可以输出额外日志或报告错误,避免程序直接崩溃。
18当JavaScript中的Promise被拒绝,而这个拒绝又没有被catch处理时,系统就会抛出一个Promise Reject,同时系统会调用用户提前设置的处理Promise Reject的函数。在这个处理函数中,用户可以处理未捕获的Promise拒绝。
19
20## 接口说明
21
22| 接口                       | 功能说明                            |
23|----------------------------|-------------------------------------|
24| OH_JSVM_SetHandlerForOOMError         | 用于在VM中设置处理OOM Error的函数|
25| OH_JSVM_SetHandlerForFatalError   | 用于在VM中设置处理Fatal Error的函数|
26| OH_JSVM_SetHandlerForPromiseReject | 用于在VM中设置处理Promise Reject的函数 |
27
28## 使用示例
29
30JSVM-API接口开发流程参考[使用JSVM-API实现JS与C/C++语言交互开发流程](use-jsvm-process.md),本文仅对接口对应C++相关代码进行展示。
31
32### OH_JSVM_SetHandlerForOOMError
33通过OH_JSVM_SetHandlerForOOMError,用户可以设置处理OOM Error的函数。当多次调用这个API进行函数设置时,仅最后一次设置会生效。当用户传入的设置函数为NULL时,则表示取消之前设置的处理函数。
34
35**cpp部分代码:**
36
37```cpp
38#include <csetjmp>
39#include <vector>
40
41static jmp_buf buf;
42static bool oomHandlerFinished = false;
43
44void OnOOMError(const char *location, const char *detail, bool isHeapOOM)
45{
46    oomHandlerFinished = true;
47    longjmp(buf, 1);
48}
49
50static JSVM_Value TriggerOOMError(JSVM_Env env, JSVM_CallbackInfo info)
51{
52    oomHandlerFinished = false;
53    JSVM_VM vm;
54    JSVM_CALL(OH_JSVM_GetVM(env, &vm));
55    // 设置OOM Error处理函数
56    JSVM_CALL(OH_JSVM_SetHandlerForOOMError(vm, OnOOMError));
57    bool oomed = false;
58    setjmp(buf);
59    if (!oomed) {
60        oomed = true;
61        // 触发OOM
62        std::vector<JSVM_Value> arrayVec;
63        int loopCount = 1000;
64        for (int i = 0; i < loopCount; i++) {
65            JSVM_Value array;
66            JSVM_CALL(OH_JSVM_CreateArrayWithLength(env, 0xffffff, &array));
67            arrayVec.push_back(array);
68        }
69    }
70    if (oomHandlerFinished) {
71        OH_LOG_INFO(LOG_APP, "JSVM Trigger OOM Error: success");
72    } else {
73        OH_LOG_ERROR(LOG_APP, "JSVM Trigger OOM Error: failed");
74    }
75    // 取消对OOM Error处理函数的设置
76    JSVM_CALL(OH_JSVM_SetHandlerForOOMError(vm, NULL));
77    JSVM_Value checked;
78    OH_JSVM_GetBoolean(env, true, &checked);
79    return checked;
80}
81
82static JSVM_CallbackStruct param[] = {
83    {.data = nullptr, .callback = TriggerOOMError},
84};
85static JSVM_CallbackStruct *method = param;
86
87static JSVM_PropertyDescriptor descriptor[] = {
88    {"triggerOOMError", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
89};
90```
91**样例测试JS**
92```cpp
93const char *srcCallNative = R"JS(triggerOOMError();)JS";
94```
95**执行结果**
96
97在LOG中输出: 
98```cpp
99JSVM Trigger OOM Error: success
100```
101### OH_JSVM_SetHandlerForFatalError
102通过OH_JSVM_SetHandlerForFatalError,用户可以设置处理Fatal Error的函数。当多次调用这个API进行函数设置时,仅最后一次设置会生效。当用户传入的设置函数为NULL时,则表示取消之前设置的处理函数。
103**cpp部分代码:**
104
105```cpp
106#include <csetjmp>
107#include <vector>
108
109static jmp_buf buf;
110static bool fatalHandlerFinished = false;
111void OnFatalError(const char *location, const char *message)
112{
113    fatalHandlerFinished = true;
114    OH_LOG_INFO(LOG_APP, "Run in 106");
115    longjmp(buf, 1);
116}
117
118static JSVM_Value TriggerFatalError(JSVM_Env env, JSVM_CallbackInfo info)
119{
120    fatalHandlerFinished = false;
121    JSVM_VM vm;
122    JSVM_CALL(OH_JSVM_GetVM(env, &vm));
123    // 设置Fatal Error处理函数
124    JSVM_CALL(OH_JSVM_SetHandlerForFatalError(vm, OnFatalError));
125    bool fataled = false;
126    setjmp(buf);
127    if (!fataled) {
128        fataled = true;
129        std::vector<JSVM_Value> arrayVec;
130        int loopCount = 1000;
131        for (int i = 0; i < loopCount; i++) {
132            JSVM_Value array;
133            JSVM_CALL(OH_JSVM_CreateArrayWithLength(env, 0xffffff, &array));
134            arrayVec.push_back(array);
135        }
136    }
137    if (fatalHandlerFinished) {
138        OH_LOG_INFO(LOG_APP, "JSVM Trigger Fatal Error: success");
139    } else {
140        OH_LOG_ERROR(LOG_APP, "JSVM Trigger Fatal Error: failed");
141    }
142    // 取消对Fatal Error处理函数的设置
143    JSVM_CALL(OH_JSVM_SetHandlerForFatalError(vm, NULL));
144    JSVM_Value checked;
145    OH_JSVM_GetBoolean(env, true, &checked);
146    return checked;
147}
148
149static JSVM_CallbackStruct param[] = {
150    {.data = nullptr, .callback = TriggerFatalError},
151};
152static JSVM_CallbackStruct *method = param;
153
154static JSVM_PropertyDescriptor descriptor[] = {
155    {"triggerFatalError", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
156};
157```
158**样例测试JS**
159```cpp
160const char* srcCallNative = R"JS(triggerFatalError())JS";
161```
162**执行结果:**
163
164在LOG中输出: 
165```cpp
166JSVM Trigger Fatal Error: success
167```
168### OH_JSVM_SetHandlerForPromiseReject
169通过OH_JSVM_SetHandlerForPromiseReject,用户可以设置处理Promise Reject的函数。当多次调用这个API进行函数设置时,仅最后一次设置会生效。当用户传入的设置函数为NULL时,则表示取消之前设置的处理函数。
170**cpp部分代码:**
171
172```cpp
173static bool promiseRejectHandlerFinished = false;
174
175void OnPromiseReject(JSVM_Env env, JSVM_PromiseRejectEvent rejectEvent, JSVM_Value rejectInfo)
176{
177    bool result = false;
178    OH_JSVM_IsObject(env, rejectInfo, &result);
179    JSVM_Value promise;
180    JSVM_Value key1;
181    OH_JSVM_CreateStringUtf8(env, "promise", JSVM_AUTO_LENGTH, &key1);
182    OH_JSVM_GetProperty(env, rejectInfo, key1, &promise);
183    bool isPromise = false;
184    OH_JSVM_IsPromise(env, promise, &isPromise);
185    JSVM_Value value;
186    JSVM_Value key2;
187    OH_JSVM_CreateStringUtf8(env, "value", JSVM_AUTO_LENGTH, &key2);
188    OH_JSVM_GetProperty(env, rejectInfo, key2, &value);
189    JSVM_Value js_number;
190    OH_JSVM_CoerceToNumber(env, value, &js_number);
191    double res = 0;
192    OH_JSVM_GetValueDouble(env, js_number, &res);
193    if (res == 42 && isPromise) {
194        promiseRejectHandlerFinished = true;
195    }
196}
197
198static JSVM_Value TriggerPromiseReject(JSVM_Env env, JSVM_CallbackInfo info)
199{
200    promiseRejectHandlerFinished = false;
201    JSVM_VM vm;
202    JSVM_CALL(OH_JSVM_GetVM(env, &vm));
203    // 设置Promise Reject处理函数
204    JSVM_CALL(OH_JSVM_SetHandlerForPromiseReject(vm, OnPromiseReject));
205    JSVM_Value strVal;
206    char *str = "new Promise((resolve, reject) => { reject(42); })";
207    OH_JSVM_CreateStringUtf8(env, str, JSVM_AUTO_LENGTH, &strVal);
208    JSVM_Script script;
209    OH_JSVM_CompileScript(env, strVal, nullptr, 0, false, nullptr, &script);
210    JSVM_Value result;
211    JSVM_Status status = OH_JSVM_RunScript(env, script, &result);
212
213    if (promiseRejectHandlerFinished) {
214        OH_LOG_INFO(LOG_APP, "JSVM Trigger Promise Reject: success");
215    } else {
216        OH_LOG_ERROR(LOG_APP, "JSVM Trigger Promise Reject: failed");
217    }
218    // 取消对Promise Reject处理函数的设置
219    JSVM_CALL(OH_JSVM_SetHandlerForPromiseReject(vm, NULL));
220    JSVM_Value checked;
221    OH_JSVM_GetBoolean(env, true, &checked);
222    return checked;
223}
224
225static JSVM_CallbackStruct param[] = {
226    {.data = nullptr, .callback = TriggerPromiseReject},
227};
228static JSVM_CallbackStruct *method = param;
229
230static JSVM_PropertyDescriptor descriptor[] = {
231    {"triggerPromiseReject", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
232};
233```
234**样例测试JS**
235```cpp
236const char* srcCallNative = R"JS(triggerPromiseReject())JS";
237```
238**执行结果:**
239
240在LOG中输出: 
241```cpp
242JSVM Trigger Promise Reject: success
243```