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