使用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++语言交互开发流程](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/use-jsvm-process)，本文仅对接口对应C++相关代码进行展示。

#### \[h2\]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

#### \[h2\]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

#### \[h2\]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;
    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