# 使用JSVM-API进行异常的定制化处理

#### 简介

JSVM-API提供了一组用于处理JSVM异常的接口。通过这些接口，可以向JSVM注册回调函数。当JSVM触发异常时，会调用已注册的回调函数。

这些接口提供对JS引擎错误的定制化处理，帮助开发者管理运行时错误和异常。

#### 基本概念

当JS引擎遇到内存不足的问题时，系统会抛出一个OOM Error，如果开发者提前向JS引擎中注册了OOM Error的处理函数，系统就会调用这个设置的处理函数，开发者可以在处理函数中执行一些清理或者日志记录操作。

当JS引擎发生致命错误，例如执行JavaScript代码时出现无法恢复的错误，系统会抛出一个Fatal Error，并调用用户预先设置的处理函数。在该处理函数中，可以输出额外日志或报告错误，避免程序直接崩溃。

当JavaScript中的Promise被拒绝，而这个拒绝又没有被catch处理时，系统就会抛出一个Promise Reject，同时系统会调用用户提前设置的处理Promise Reject的函数。在这个处理函数中，用户可以处理未捕获的Promise拒绝。

#### 接口说明

| 接口 | 功能说明 |
| --- | --- |
| OH_JSVM_SetHandlerForOOMError | 用于在VM中设置处理OOM Error的函数 |
| OH_JSVM_SetHandlerForFatalError | 用于在VM中设置处理Fatal Error的函数 |
| OH_JSVM_SetHandlerForPromiseReject | 用于在VM中设置处理Promise Reject的函数 |

#### 使用示例

JSVM-API接口开发流程参考使用JSVM-API实现JS与C/C++语言交互开发流程，本文仅对接口对应C++相关代码进行展示。

#### OH\_JSVM\_SetHandlerForOOMError

通过OH\_JSVM\_SetHandlerForOOMError，用户可以设置处理OOM Error的函数。当多次调用这个API进行函数设置时，仅最后一次设置会生效。当用户传入的设置函数为NULL时，则表示取消之前设置的处理函数。

**cpp部分代码：**

```
#include <csetjmp>
#include <vector>

static jmp_buf buf;
static bool oomHandlerFinished = false;

void OnOOMError(const char *location, const char *detail, bool isHeapOOM)
{
    oomHandlerFinished = true;
    longjmp(buf, 1);
}

static JSVM_Value TriggerOOMError(JSVM_Env env, JSVM_CallbackInfo info)
{
    oomHandlerFinished = false;
    JSVM_VM vm;
    JSVM_CALL(OH_JSVM_GetVM(env, &vm));
    // 设置OOM Error处理函数
    JSVM_CALL(OH_JSVM_SetHandlerForOOMError(vm, OnOOMError));
    bool oomed = false;
    setjmp(buf);
    if (!oomed) {
        oomed = true;
        // 触发OOM
        std::vector<JSVM_Value> arrayVec;
        int loopCount = 1000;
        for (int i = 0; i < loopCount; i++) {
            JSVM_Value array;
            JSVM_CALL(OH_JSVM_CreateArrayWithLength(env, 0xffffff, &array));
            arrayVec.push_back(array);
        }
    }
    if (oomHandlerFinished) {
        OH_LOG_INFO(LOG_APP, "JSVM Trigger OOM Error: success");
    } else {
        OH_LOG_ERROR(LOG_APP, "JSVM Trigger OOM Error: failed");
    }
    // 取消对OOM Error处理函数的设置
    JSVM_CALL(OH_JSVM_SetHandlerForOOMError(vm, NULL));
    JSVM_Value checked;
    OH_JSVM_GetBoolean(env, true, &checked);
    return checked;
}

static JSVM_CallbackStruct param[] = {
    {.data = nullptr, .callback = TriggerOOMError},
};
static JSVM_CallbackStruct *method = param;

static JSVM_PropertyDescriptor descriptor[] = {
    {"triggerOOMError", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
};
```

**样例测试JS**

```
const char *srcCallNative = R"JS(triggerOOMError();)JS";
```

**执行结果**

在LOG中输出：

```
JSVM Trigger OOM Error: success
```

#### OH\_JSVM\_SetHandlerForFatalError

通过OH\_JSVM\_SetHandlerForFatalError，用户可以设置处理Fatal Error的函数。当多次调用这个API进行函数设置时，仅最后一次设置会生效。当用户传入的设置函数为NULL时，则表示取消之前设置的处理函数。

**cpp部分代码：**

```
#include <csetjmp>
#include <vector>

static jmp_buf buf;
static bool fatalHandlerFinished = false;
void OnFatalError(const char *location, const char *message)
{
    fatalHandlerFinished = true;
    OH_LOG_INFO(LOG_APP, "Run in 106");
    longjmp(buf, 1);
}

static JSVM_Value TriggerFatalError(JSVM_Env env, JSVM_CallbackInfo info)
{
    fatalHandlerFinished = false;
    JSVM_VM vm;
    JSVM_CALL(OH_JSVM_GetVM(env, &vm));
    // 设置Fatal Error处理函数
    JSVM_CALL(OH_JSVM_SetHandlerForFatalError(vm, OnFatalError));
    bool fataled = false;
    setjmp(buf);
    if (!fataled) {
        fataled = true;
        std::vector<JSVM_Value> arrayVec;
        int loopCount = 1000;
        for (int i = 0; i < loopCount; i++) {
            JSVM_Value array;
            JSVM_CALL(OH_JSVM_CreateArrayWithLength(env, 0xffffff, &array));
            arrayVec.push_back(array);
        }
    }
    if (fatalHandlerFinished) {
        OH_LOG_INFO(LOG_APP, "JSVM Trigger Fatal Error: success");
    } else {
        OH_LOG_ERROR(LOG_APP, "JSVM Trigger Fatal Error: failed");
    }
    // 取消对Fatal Error处理函数的设置
    JSVM_CALL(OH_JSVM_SetHandlerForFatalError(vm, NULL));
    JSVM_Value checked;
    OH_JSVM_GetBoolean(env, true, &checked);
    return checked;
}

static JSVM_CallbackStruct param[] = {
    {.data = nullptr, .callback = TriggerFatalError},
};
static JSVM_CallbackStruct *method = param;

static JSVM_PropertyDescriptor descriptor[] = {
    {"triggerFatalError", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
};
```

**样例测试JS**

```
const char* srcCallNative = R"JS(triggerFatalError())JS";
```

**执行结果：**

在LOG中输出：

```
JSVM Trigger Fatal Error: success
```

#### OH\_JSVM\_SetHandlerForPromiseReject

通过OH\_JSVM\_SetHandlerForPromiseReject，用户可以设置处理Promise Reject的函数。当多次调用这个API进行函数设置时，仅最后一次设置会生效。当用户传入的设置函数为NULL时，则表示取消之前设置的处理函数。

**cpp部分代码：**

```
static bool promiseRejectHandlerFinished = false;

void OnPromiseReject(JSVM_Env env, JSVM_PromiseRejectEvent rejectEvent, JSVM_Value rejectInfo)
{
    bool result = false;
    OH_JSVM_IsObject(env, rejectInfo, &result);
    JSVM_Value promise;
    JSVM_Value key1;
    OH_JSVM_CreateStringUtf8(env, "promise", JSVM_AUTO_LENGTH, &key1);
    OH_JSVM_GetProperty(env, rejectInfo, key1, &promise);
    bool isPromise = false;
    OH_JSVM_IsPromise(env, promise, &isPromise);
    JSVM_Value value;
    JSVM_Value key2;
    OH_JSVM_CreateStringUtf8(env, "value", JSVM_AUTO_LENGTH, &key2);
    OH_JSVM_GetProperty(env, rejectInfo, key2, &value);
    JSVM_Value js_number;
    OH_JSVM_CoerceToNumber(env, value, &js_number);
    double res = 0;
    OH_JSVM_GetValueDouble(env, js_number, &res);
    if (res == 42 && isPromise) {
        promiseRejectHandlerFinished = true;
    }
}

static JSVM_Value TriggerPromiseReject(JSVM_Env env, JSVM_CallbackInfo info)
{
    promiseRejectHandlerFinished = false;
    JSVM_VM vm;
    JSVM_CALL(OH_JSVM_GetVM(env, &vm));
    // 设置Promise Reject处理函数
    JSVM_CALL(OH_JSVM_SetHandlerForPromiseReject(vm, OnPromiseReject));
    JSVM_Value strVal;
    const char *str = "new Promise((resolve, reject) => { reject(42); })";
    OH_JSVM_CreateStringUtf8(env, str, JSVM_AUTO_LENGTH, &strVal);
    JSVM_Script script;
    OH_JSVM_CompileScript(env, strVal, nullptr, 0, false, nullptr, &script);
    JSVM_Value result;
    JSVM_Status status = OH_JSVM_RunScript(env, script, &result);

    if (promiseRejectHandlerFinished) {
        OH_LOG_INFO(LOG_APP, "JSVM Trigger Promise Reject: success");
    } else {
        OH_LOG_ERROR(LOG_APP, "JSVM Trigger Promise Reject: failed");
    }
    // 取消对Promise Reject处理函数的设置
    JSVM_CALL(OH_JSVM_SetHandlerForPromiseReject(vm, NULL));
    JSVM_Value checked;
    OH_JSVM_GetBoolean(env, true, &checked);
    return checked;
}

static JSVM_CallbackStruct param[] = {
    {.data = nullptr, .callback = TriggerPromiseReject},
};
static JSVM_CallbackStruct *method = param;

static JSVM_PropertyDescriptor descriptor[] = {
    {"triggerPromiseReject", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
};
```

**样例测试JS**

```
const char* srcCallNative = R"JS(triggerPromiseReject())JS";
```

**执行结果：**

在LOG中输出：

```
JSVM Trigger Promise Reject: success
```