使用JSVM-API接口处理异步操作
==================

#### 简介

使用JSVM-API接口处理异步操作。异步操作是指需要一定时间才能完成的操作，例如从网络下载数据或读取大型文件。与同步操作不同，异步操作不会阻塞主线程，而是会在后台执行。当异步操作完成后，事件循环将把它放入任务队列中，等待主线程空闲时执行。

#### 基本概念

Promise是JavaScript中用来处理异步操作的对象，Promise有pending（待定）、fulfilled（已兑现）和rejected（已拒绝）三种状态，Promise的初始状态是pending，resolve函数可以使其状态从pending变为fulfilled（已兑现），reject函数可以使其状态从pending变为rejected(已拒绝)，一旦兑现或拒绝Promise的状态将不能更改。下面是一些基本概念：

*   **同步**： 同步是指代码按照顺序一行一行地执行，每行代码的执行都会等待上一行代码执行完成后再继续执行。在同步执行中，如果某个操作需要花费较长时间，那么整个程序的执行就会被阻塞，直到该操作完成才能继续执行后续代码。
*   **异步**：异步是指任务可以同时执行，不需要等待上一个任务结束。在JavaScript中，常见的异步操作包括定时器、事件监听、网络请求等。异步任务不会阻塞后续任务的执行，而是通过回调函数或Promise对象来处理任务的结果。
*   **Promise**：Promise是一个JavaScript对象，用于处理异步操作。Promise作用于外部，通常通过then、catch和finally方法暴露给外部以添加自定义逻辑。
*   **deferred**：deferred是延迟对象，它可以与Promise对象关联，设置Promise的回调函数resolve和reject。deferred作用于内部，维护异步模型的状态并设置回调函数resolve和reject。
*   **resolve**：此函数可以将Promise的状态从pending（待定）改为fulfilled（已兑现），向resolve中传入的参数可以在Promise对象的then方法中获取。
*   **reject**：此函数可以将Promise的状态从pending（待定）改为rejected（已拒绝），向reject中传入的参数可以在Promise对象的catch方法中获取。

这些基本概念在处理异步操作中非常重要，开发者需要通过适当的方法来处理异步操作，Promise可以链式调用多个异步操作，使代码清晰整洁，便于维护。JSVM-API提供的方法可以帮助开发者在JSVM模块中处理JavaScript中的异步操作。

#### 接口说明

| 接口 | 功能说明 |
| :-- | :-- |
| OH\_JSVM\_IsPromise | 查询Promise是否为Promise对象 |
| OH\_JSVM\_CreatePromise | 创建一个延迟对象和一个JavaScript promise |
| OH\_JSVM\_ResolveDeferred | 通过与之关联的延迟对象来解析JavaScript promise |
| OH\_JSVM\_RejectDeferred | 通过与之关联的延迟对象来拒绝JavaScript promise |
| OH\_JSVM\_PromiseRegisterHandler | 为 Promise 创建兑现或拒绝后的回调 |

#### 使用示例

JSVM-API接口开发流程参考[使用JSVM-API实现JS与C/C++语言交互开发流程](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/use-jsvm-process)，本文仅对接口对应C++相关代码进行展示。

#### \[h2\]OH\_JSVM\_IsPromise

判断给定的JSVM\_Value是否表示一个Promise对象。

cpp部分代码

// hello.cpp
#include "napi/native\_api.h"
#include "ark\_runtime/jsvm.h"
#include <hilog/log.h>
// OH\_JSVM\_IsPromise的样例方法
static JSVM\_Value IsPromise(JSVM\_Env env, JSVM\_CallbackInfo info)
{
    size\_t argc = 1;
    JSVM\_Value args\[1\] = {nullptr};
    OH\_JSVM\_GetCbInfo(env, info, &argc, args, nullptr, nullptr);
    bool isPromise = false;
    JSVM\_Status status = OH\_JSVM\_IsPromise(env, args\[0\], &isPromise);
    if (status != JSVM\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "JSVM OH\_JSVM\_IsPromise fail");
    } else {
        OH\_LOG\_INFO(LOG\_APP, "JSVM OH\_JSVM\_IsPromise success:%{public}d", isPromise);
    }
    JSVM\_Value result = nullptr;
    OH\_JSVM\_GetBoolean(env, isPromise, &result);
    return result;
}
// IsPromise注册回调
static JSVM\_CallbackStruct param\[\] = {
    {.data = nullptr, .callback = IsPromise},
};
static JSVM\_CallbackStruct \*method = param;
// IsPromise方法别名，供JS调用
static JSVM\_PropertyDescriptor descriptor\[\] = {
    {"isPromise", nullptr, method++, nullptr, nullptr, nullptr, JSVM\_DEFAULT},
};

// 样例测试js
const char \*srcCallNative = R"JS(isPromise())JS";

预期结果：

JSVM OH\_JSVM\_IsPromise success:0

#### \[h2\]OH\_JSVM\_CreatePromise

OH\_JSVM\_CreatePromise用于创建一个Promise对象。

#### \[h2\]OH\_JSVM\_ResolveDeferred & OH\_JSVM\_RejectDeferred

用于对Promise关联的deferred对象进行解析，OH\_JSVM\_ResolveDeferred将其从挂起状态转换为已兑现状态，OH\_JSVM\_RejectDeferred将其从挂起状态转换为已拒绝状态。

cpp部分代码

// hello.cpp
#include "napi/native\_api.h"
#include "ark\_runtime/jsvm.h"
#include <hilog/log.h>
// OH\_JSVM\_CreatePromise、OH\_JSVM\_ResolveDeferred、OH\_JSVM\_RejectDeferred的样例方法
static JSVM\_Value CreatePromise(JSVM\_Env env, JSVM\_CallbackInfo info)
{
    JSVM\_Deferred defer = nullptr;
    JSVM\_Value promise = nullptr;
    JSVM\_Status status = OH\_JSVM\_CreatePromise(env, &defer, &promise);
    bool isPromise = false;
    JSVM\_Value returnIsPromise = nullptr;
    OH\_JSVM\_IsPromise(env, promise, &isPromise);
    if (status != JSVM\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "JSVM CreatePromise fail");
    } else {
        OH\_LOG\_INFO(LOG\_APP, "JSVM CreatePromise success:%{public}d", isPromise);
    }
    // 将布尔值转为可以返回的JSVM\_Value
    OH\_JSVM\_GetBoolean(env, isPromise, &returnIsPromise);
    return returnIsPromise;
}

static JSVM\_Value ResolveRejectDeferred(JSVM\_Env env, JSVM\_CallbackInfo info)
{
    // 获得并解析参数
    size\_t argc = 3;
    JSVM\_Value args\[3\] = {nullptr};
    OH\_JSVM\_GetCbInfo(env, info, &argc, args, nullptr, nullptr);
    // 第一个参数为向resolve传入的信息，第二个参数为向reject传入的信息，第三个参数为Promise的状态
    bool status = false;
    OH\_JSVM\_GetValueBool(env, args\[2\], &status);
    // 创建Promise对象
    JSVM\_Deferred deferred = nullptr;
    JSVM\_Value promise = nullptr;
    JSVM\_Status createStatus = OH\_JSVM\_CreatePromise(env, &deferred, &promise);
    if (createStatus != JSVM\_OK) {
        OH\_JSVM\_ThrowError(env, nullptr, "Create promise failed");
        return nullptr;
    }
    // 根据第三个参数设置resolve或reject
    if (status) {
        OH\_JSVM\_ResolveDeferred(env, deferred, args\[0\]);
        OH\_LOG\_INFO(LOG\_APP, "OH\_JSVM\_ResolveDeferred resolve");
    } else {
        OH\_JSVM\_RejectDeferred(env, deferred, args\[1\]);
        OH\_LOG\_INFO(LOG\_APP, "OH\_JSVM\_RejectDeferred reject");
    }
    JSVM\_Value result = nullptr;
    OH\_JSVM\_GetBoolean(env, true, &result);
    return result;
}
// CreatePromise,ResolveRejectDeferred注册回调
static JSVM\_CallbackStruct param\[\] = {
    {.data = nullptr, .callback = CreatePromise},
    {.data = nullptr, .callback = ResolveRejectDeferred},
};
static JSVM\_CallbackStruct \*method = param;
// CreatePromise,ResolveRejectDeferred方法别名，供JS调用
static JSVM\_PropertyDescriptor descriptor\[\] = {
    {"createPromise", nullptr, method++, nullptr, nullptr, nullptr, JSVM\_DEFAULT},
    {"resolveRejectDeferred", nullptr, method++, nullptr, nullptr, nullptr, JSVM\_DEFAULT},
};

// 样例测试js
const char \*srcCallNative = R"JS(createPromise();
                                 resolveRejectDeferred('success', 'fail', true);
                                 resolveRejectDeferred('success', 'fail', false);)JS";

预期结果：

JSVM CreatePromise success:1
OH\_JSVM\_ResolveDeferred resolve
OH\_JSVM\_RejectDeferred reject

#### OH\_JSVM\_PromiseRegisterHandler

用于设置 Promise 解析或拒绝后的回调，等效于调用原生的 Promise.then() 或 Promise.catch()。

以下仅对 cpp 部分代码进行展示，其余框架代码如 TestJSVM 函数参考 [使用JSVM-API接口进行任务队列相关开发](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/use-jsvm-execute_tasks) OH\_JSVM\_SetMicrotaskPolicy 段落中的实现。

static int PromiseRegisterHandler(JSVM\_VM vm, JSVM\_Env env) {
    const char \*defineFunction = R"JS(
        var x1 = 0;
        var x2 = 0;
        function f1(x) {
            x1 = x;
            return x + 1;
        }
        function f2(x) {
            x2 = x;
            return x + 1;
        }
    )JS";

    const char \*init = R"JS(
        x1 = 0;
        x2 = 0;
    )JS";

    JSVM\_Script script;
    JSVM\_Value jsSrc;
    JSVM\_Value result;

    // 定义 JS 函数 f1 和 f2
    CHECK\_RET(OH\_JSVM\_CreateStringUtf8(env, defineFunction, JSVM\_AUTO\_LENGTH, &jsSrc));
    CHECK\_RET(OH\_JSVM\_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script));
    CHECK\_RET(OH\_JSVM\_RunScript(env, script, &result));

    // 初始化 x1， x2 为 0
    CHECK\_RET(OH\_JSVM\_CreateStringUtf8(env, init, JSVM\_AUTO\_LENGTH, &jsSrc));
    CHECK\_RET(OH\_JSVM\_CompileScript(env, jsSrc, nullptr, 0, true, nullptr, &script));
    CHECK\_RET(OH\_JSVM\_RunScript(env, script, &result));

    // 获取函数 f1 和 f2
    JSVM\_Value global;
    CHECK\_RET(OH\_JSVM\_GetGlobal(env, &global));
    JSVM\_Value f1;
    CHECK\_RET(OH\_JSVM\_GetNamedProperty(env, global, "f1", &f1));
    JSVM\_Value f2;
    CHECK\_RET(OH\_JSVM\_GetNamedProperty(env, global, "f2", &f2));

    // 创建 Promise
    JSVM\_Value promise;
    JSVM\_Deferred deferred;
    CHECK\_RET(OH\_JSVM\_CreatePromise(env, &deferred, &promise));
    // 为 promise 注册回调函数，并将 then 调用的结果（新的 Promise）赋值给 promise1
    JSVM\_Value promise1;
    CHECK\_RET(OH\_JSVM\_PromiseRegisterHandler(env, promise, f1, nullptr, &promise1));
    // 为 promise1 注册回调函数
    CHECK\_RET(OH\_JSVM\_PromiseRegisterHandler(env, promise1, f2, nullptr, nullptr));

    // 获取 promise 解析前 x1 和 x2 的值
    JSVM\_Value x1;
    CHECK\_RET(OH\_JSVM\_GetNamedProperty(env, global, "x1", &x1));
    int32\_t x1Int = 0;
    CHECK\_RET(OH\_JSVM\_GetValueInt32(env, x1, &x1Int));
    JSVM\_Value x2;
    CHECK\_RET(OH\_JSVM\_GetNamedProperty(env, global, "x2", &x2));
    int32\_t x2Int = 0;
    CHECK\_RET(OH\_JSVM\_GetValueInt32(env, x2, &x2Int));
    OH\_LOG\_INFO(LOG\_APP, "Before promise resolved, x1: %{public}d, x2: %{public}d", x1Int, x2Int);

    // 解析 promise
    JSVM\_Value resolveValue;
    CHECK\_RET(OH\_JSVM\_CreateInt32(env, 2, &resolveValue));
    if (deferred != nullptr) {
        OH\_JSVM\_ResolveDeferred(env, deferred, resolveValue);
        deferred = nullptr;
    }

    // 获取 promise 解析后 x1 和 x2 的值
    CHECK\_RET(OH\_JSVM\_GetNamedProperty(env, global, "x1", &x1));
    CHECK\_RET(OH\_JSVM\_GetValueInt32(env, x1, &x1Int));
    CHECK\_RET(OH\_JSVM\_GetNamedProperty(env, global, "x2", &x2));
    CHECK\_RET(OH\_JSVM\_GetValueInt32(env, x2, &x2Int));
    OH\_LOG\_INFO(LOG\_APP, "After promise resolved, x1: %{public}d, x2: %{public}d", x1Int, x2Int);

    return 0;
}

static void RunDemo(JSVM\_VM vm, JSVM\_Env env) {
    if (PromiseRegisterHandler(vm, env) != 0) {
        OH\_LOG\_INFO(LOG\_APP, "Run PromiseRegisterHandler failed");
    }
}

预期结果：

Before promise resolved, x1: 0, x2: 0
After promise resolved, x1: 2, x2: 3