# 16.6:NAPI异步编程

笔者在前 5 小节里讲述了在 OpenHarmony 上通过 NAPI 的方式实现了 JS 调用 C++的能力,但是这些实现都是同步的,本节笔者简单介绍一下 NAPI 的异步实现。

# 16.6.1:约定编程规范

ArkUI 开发框架对外提供的 API 命名是需遵守一定规范的,以 @ohos.display 模块提供的 API 为例,源码如下所示:

declare namespace display {
    function getDefaultDisplay(callback: AsyncCallback<Display>): void;
    function getDefaultDisplay(): Promise<Display>;
    function getDefaultDisplaySync(): Display;
}
1
2
3
4
5

根据该模块提供的方法,根据方法的命名规则可以得出 2 条规范:

  • 同步调用:

    • 方法名+ Sync 关键字,如:getMd5Sync():string
  • 异步调用:

    • 需要提供 AsyncCallbackPromise 的实现,如:getMd5(): Promise<string>getMd5(callback: AsyncCallback<Display>)

因此,我们在 index.d.ts 中声明 NAPI 方法时也按照系统约定的规范来。

# 16.6.2:定义异步方法

笔者在第 5 小结实现了 MD5 的计算,本节笔者把 MD5 的实现放在异步线程中,先在 index.d.ts 声明 JS 侧的方法,如下所示:

export const add: (a: number, b: number) => number;

// 声明异步方法
export function getMd5(value: string, callback: (md5: string) => void): void;
export function getMd5(value: string): Promise<string>;

// 声明同步方法
export function getMd5Sync(value: string): string;
1
2
3
4
5
6
7
8

getMd5Sync()表示同步实现 MD5 的计算,getMd5() 表示异步实现 MD5 的调用。

# 16.6.3:实现异步方法

声明完 JS 端的方法后,接着在 hello.cpp 中实现对应的方法,步骤如下:

  • 添加映射

    hello.cppInit() 方法里添加 JS 端的方法映射,代码如下所示:

    static napi_value Init(napi_env env, napi_value exports) {
        napi_property_descriptor desc[] = {
            {"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
            {"getMd5Sync", nullptr, GetMd5Sync, nullptr, nullptr, nullptr, napi_default, nullptr},
            {"getMd5", nullptr, GetMd5, nullptr, nullptr, nullptr, napi_default, nullptr},
        };
    
        napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
        return exports;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    "getMd5Sync"GetMd5Sync 分别表示 JS 端和 C++ 端的方法,通过 napi_define_properties() 把他们映射在一起。

  • 方法实现

    getMd5() 的 C++ 端代码如下所示:

    // 定义异步线程执行中需要的上下文环境
    struct Md5Context {
        // 异步 worker
        napi_async_work work;
    
        // 对应 JS 端的 callback 函数
        napi_ref callback;
    
        // 对应 JS 端的 promise 对象
        napi_deferred promise;
    
        // 传递进来的参数
        string params;
        // 计算后的结果
        string result;
    };
    
    // 在子线程中执行
    static void doInBackground(napi_env env, void *data) {
        Md5Context *md5Context = (Md5Context *)data;
    
        // 模拟耗时操作,进行 MD5 计算
        string md5 = MD5(md5Context->params).toStr();
    
        // 计算后的 MD5 字存储到 result 中
        md5Context->result = md5;
        
        // 模拟耗时操作,让当前线程休眠 3 秒钟
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }
    
    // 切换到主线程
    static void onPostExecutor(napi_env env, napi_status status, void *data) {
        Md5Context *md5Context = (Md5Context *)data;
    
        napi_value returnValue;
        if (napi_ok !=
            napi_create_string_utf8(env, md5Context->result.c_str(), md5Context->result.length(), &returnValue)) {
            delete md5Context;
            md5Context = nullptr;
            napi_throw_error(env, "-111", "napi_create_string_utf8: error");
            return;
        }
    
        if (md5Context->callback) {
            // 取出缓存的 js 端的 callback
            napi_value callback;
            if (napi_ok != napi_get_reference_value(env, md5Context->callback, &callback)) {
                delete md5Context;
                md5Context = nullptr;
                napi_throw_error(env, "-111", "napi_get_reference_value error");
                return;
            }
    
            napi_value tempValue;
            // 调用 callback,把值回调给 JS 端
            napi_call_function(env, nullptr, callback, 1, &returnValue, &tempValue);
            // 删除 callback
            napi_delete_reference(env, md5Context->callback);
        } else {
            // 以 promise 的形式回调数据
            if (napi_ok != napi_resolve_deferred(env, md5Context->promise, returnValue)) {
                delete md5Context;
                md5Context = nullptr;
                napi_throw_error(env, "-111", "napi_resolve_deferred error");
            }
        }
    
        // 删除异步任务并释放资源
        napi_delete_async_work(env, md5Context->work);
        delete md5Context;
        md5Context = nullptr;
    }
    
    
    static napi_value GetMd5(napi_env env, napi_callback_info info) {
        // 1、从 info 中读取 JS 传递过来的参数放入 args 里
        size_t argc = 2;
        napi_value args[2] = {nullptr};
        if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) {
            napi_throw_error(env, "-1001", "napi_get_cb_info error");
            return nullptr;
        }
    
        // 2、读取传入的参数类型
        napi_valuetype stringType = napi_undefined;
        if (napi_ok != napi_typeof(env, args[0], &stringType)) {
            napi_throw_error(env, "-1002", "napi_typeof string error");
            return nullptr;
        }
    
        // 3、传入的 string 如果为 null 或者 undefined 则抛异常
        if (napi_null == stringType || napi_undefined == stringType) {
            napi_throw_error(env, "-1003", "input params null or undefined");
            return nullptr;
        }
    
        // 4、读取传入的 string 内容长度
        size_t length = 0;
        if (napi_ok != napi_get_value_string_utf8(env, args[0], nullptr, 0, &length)) {
            napi_throw_error(env, "-1004", "get string length error");
            return nullptr;
        }
    
        // 5、判断传入的 string 长度是否符合
        if (0 == length) {
            napi_throw_error(env, "-1005", "string length can't be zero");
            return nullptr;
        }
    
        // 6、读取传入的 string 长度读取内容
        char *buffer = new char[length + 1];
        if (napi_ok != napi_get_value_string_utf8(env, args[0], buffer, length + 1, &length)) {
            delete[] buffer;
            buffer = nullptr;
            napi_throw_error(env, "-1006", "napi_get_value_string_utf8 string error");
            return nullptr;
        }
    
        // 7、读取 JS 有没有传递 callback,如果 callback 为 null 就表示是 promise 的回调方式
        napi_valuetype callbackType = napi_undefined;
        napi_status callbackStatus = napi_typeof(env, args[1], &callbackType);
        if (napi_ok != callbackStatus && napi_invalid_arg != callbackStatus) {
            delete[] buffer;
            buffer = nullptr;
            napi_throw_error(env, "-1004", "napi_typeof function error");
            return nullptr;
        }
    
        // 8、创建一个异步线程需要的数据 model,把传递过来的参数加入进去做下缓存
        auto context = new Md5Context();
        context->params = buffer;
    
        napi_value returnValue = nullptr;
    
        // 9、判断是 callback 的回调方式还是 promise 的回调方式
        if (napi_function == callbackType) {
            // 如果是 callback 的回调方式,需要创建 callback 的引用
            napi_ref callback;
            if (napi_ok != napi_create_reference(env, args[1], 1, &callback)) {
                delete[] buffer;
                delete context;
                buffer = nullptr;
                context = nullptr;
    
                napi_throw_error(env, "-11", "napi_create_reference error");
                return nullptr;
            }
    
            // 缓存 callback
            context->callback = callback;
    
            // 临时返回一个 undefined 值给 JS 端
            napi_get_undefined(env, &returnValue);
        } else {
            // promise 的回调方式,创建一个 Promise 的引用
            napi_deferred promise;
            if (napi_ok != napi_create_promise(env, &promise, &returnValue)) {
                delete[] buffer;
                delete context;
                buffer = nullptr;
                context = nullptr;
    
                napi_throw_error(env, "-11", "napi_create_promise error");
                return nullptr;
            }
    
            // 缓存 promise
            context->promise = promise;
        }
    
        napi_value resourceName;
        if (napi_ok != napi_create_string_utf8(env, "GetMd5", NAPI_AUTO_LENGTH, &resourceName)) {
            delete[] buffer;
            delete context;
            buffer = nullptr;
            context = nullptr;
            napi_throw_error(env, "-11", "napi_create_string_utf8 resourceName error");
            return nullptr;
        }
    
        // 10、创建一个异步任务
        napi_async_work asyWork;
    
        napi_status status =
            napi_create_async_work(env, nullptr, resourceName, doInBackground, onPostExecutor, (void *)context, &asyWork);
        if (napi_ok != status) {
            delete[] buffer;
            delete context;
            buffer = nullptr;
            context = nullptr;
    
            napi_throw_error(env, "-11", "napi_create_async_work error");
            return nullptr;
        }
    
        // 11、保存异步任务
        context->work = asyWork;
    
        // 12、添加进异步队列
        napi_queue_async_work(env, asyWork);
    
        return returnValue;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204

    getMd5() 的代码比较多,笔者添加的注释比较清楚,前 6 个小步骤是对传递进来的参数做基础校验,第 7 步是根据参数判断当前异步执行的回调方式是 Promise 还是 Callback。第 8 步创建了一个 Md5Context 对象,它的作用是把当前相关参数缓存下来目的是接下来在异步线程里使用这些参数,第 9 步根据异步回调的方法创建 Promise 或者 Callback 然后把他们保存在 Md5Context 对象里。第 10 步创建一个异步任务,然后把异步任务添加进异步队列中。

    napi_create_async_work() 方法的第 3 、 4 个参数需要注意,doInBackground() 方法是在异步线程中执行的,onPostExecutor() 方法在异步线程结束后切换到主线程中执行。

  • 完整代码

    hello.cpp 全部代码如下所示:

    #include <cstddef>
    #include <cstring>
    #include "napi/native_api.h"
    #include <js_native_api.h>
    #include <js_native_api_types.h>
    #include <node_api.h>
    #include <node_api_types.h>
    #include <string>
    #include <thread>
    
    #include "./md5/md5.h"
    
    
    // 定义异步线程执行中需要的上下文环境
    struct Md5Context {
        // 异步 worker
        napi_async_work work;
    
        // 对应 JS 端的 callback 函数
        napi_ref callback;
    
        // 对应 JS 端的 promise 对象
        napi_deferred promise;
    
        // 传递进来的参数
        string params;
        // 计算后的结果
        string result;
    };
    
    static void doInBackground(napi_env env, void *data) {
        Md5Context *md5Context = (Md5Context *)data;
    
        // 模拟耗时操作,进行 MD5 计算
        string md5 = MD5(md5Context->params).toStr();
    
        // 计算后的 MD5 字存储到 result 中
        md5Context->result = md5;
        
        // 模拟耗时操作,让当前线程休眠 3 秒钟
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }
    
    static void onPostExecutor(napi_env env, napi_status status, void *data) {
        Md5Context *md5Context = (Md5Context *)data;
    
        napi_value returnValue;
        if (napi_ok !=
            napi_create_string_utf8(env, md5Context->result.c_str(), md5Context->result.length(), &returnValue)) {
            delete md5Context;
            md5Context = nullptr;
            napi_throw_error(env, "-111", "napi_create_string_utf8: error");
            return;
        }
    
        if (md5Context->callback) {
            // 取出缓存的 js 端的 callback
            napi_value callback;
            if (napi_ok != napi_get_reference_value(env, md5Context->callback, &callback)) {
                delete md5Context;
                md5Context = nullptr;
                napi_throw_error(env, "-111", "napi_get_reference_value error");
                return;
            }
    
            napi_value tempValue;
            // 调用 callback,把值回调给 JS 端
            napi_call_function(env, nullptr, callback, 1, &returnValue, &tempValue);
            // 删除 callback
            napi_delete_reference(env, md5Context->callback);
        } else {
            // 以 promise 的形式回调数据
            if (napi_ok != napi_resolve_deferred(env, md5Context->promise, returnValue)) {
                delete md5Context;
                md5Context = nullptr;
                napi_throw_error(env, "-111", "napi_resolve_deferred error");
            }
        }
    
        // 删除异步任务并释放资源
        napi_delete_async_work(env, md5Context->work);
        delete md5Context;
        md5Context = nullptr;
    }
    
    
    static napi_value GetMd5(napi_env env, napi_callback_info info) {
        // 1、从 info 中读取 JS 传递过来的参数放入 args 里
        size_t argc = 2;
        napi_value args[2] = {nullptr};
        if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) {
            napi_throw_error(env, "-1001", "napi_get_cb_info error");
            return nullptr;
        }
    
        // 2、读取传入的参数类型
        napi_valuetype stringType = napi_undefined;
        if (napi_ok != napi_typeof(env, args[0], &stringType)) {
            napi_throw_error(env, "-1002", "napi_typeof string error");
            return nullptr;
        }
    
        // 3、传入的 string 如果为 null 或者 undefined 则抛异常
        if (napi_null == stringType || napi_undefined == stringType) {
            napi_throw_error(env, "-1003", "input params null or undefined");
            return nullptr;
        }
    
        // 4、读取传入的 string 内容长度
        size_t length = 0;
        if (napi_ok != napi_get_value_string_utf8(env, args[0], nullptr, 0, &length)) {
            napi_throw_error(env, "-1004", "get string length error");
            return nullptr;
        }
    
        // 5、判断传入的 string 长度是否符合
        if (0 == length) {
            napi_throw_error(env, "-1005", "string length can't be zero");
            return nullptr;
        }
    
        // 6、读取传入的 string 长度读取内容
        char *buffer = new char[length + 1];
        if (napi_ok != napi_get_value_string_utf8(env, args[0], buffer, length + 1, &length)) {
            delete[] buffer;
            buffer = nullptr;
            napi_throw_error(env, "-1006", "napi_get_value_string_utf8 string error");
            return nullptr;
        }
    
        // 7、读取 JS 有没有传递 callback,如果 callback 为 null 就表示是 promise 的回调方式
        napi_valuetype callbackType = napi_undefined;
        napi_status callbackStatus = napi_typeof(env, args[1], &callbackType);
        if (napi_ok != callbackStatus && napi_invalid_arg != callbackStatus) {
            delete[] buffer;
            buffer = nullptr;
            napi_throw_error(env, "-1004", "napi_typeof function error");
            return nullptr;
        }
    
        // 8、创建一个异步线程需要的数据 model,把传递过来的参数加入进去做下缓存
        auto context = new Md5Context();
        context->params = buffer;
    
        napi_value returnValue = nullptr;
    
        // 9、判断是 callback 的回调方式还是 promise 的回调方式
        if (napi_function == callbackType) {
            // 如果是 callback 的回调方式,需要创建 callback 的引用
            napi_ref callback;
            if (napi_ok != napi_create_reference(env, args[1], 1, &callback)) {
                delete[] buffer;
                delete context;
                buffer = nullptr;
                context = nullptr;
    
                napi_throw_error(env, "-11", "napi_create_reference error");
                return nullptr;
            }
    
            // 缓存 callback
            context->callback = callback;
    
            // 临时返回一个 undefined 值给 JS 端
            napi_get_undefined(env, &returnValue);
        } else {
            // promise 的回调方式,创建一个 Promise 的引用
            napi_deferred promise;
            if (napi_ok != napi_create_promise(env, &promise, &returnValue)) {
                delete[] buffer;
                delete context;
                buffer = nullptr;
                context = nullptr;
    
                napi_throw_error(env, "-11", "napi_create_promise error");
                return nullptr;
            }
    
            // 缓存 promise
            context->promise = promise;
        }
    
        napi_value resourceName;
        if (napi_ok != napi_create_string_utf8(env, "GetMd5", NAPI_AUTO_LENGTH, &resourceName)) {
            delete[] buffer;
            delete context;
            buffer = nullptr;
            context = nullptr;
            napi_throw_error(env, "-11", "napi_create_string_utf8 resourceName error");
            return nullptr;
        }
    
        // 10、创建一个异步任务
        napi_async_work asyWork;
    
        napi_status status =
            napi_create_async_work(env, nullptr, resourceName, doInBackground, onPostExecutor, (void *)context, &asyWork);
        if (napi_ok != status) {
            delete[] buffer;
            delete context;
            buffer = nullptr;
            context = nullptr;
    
            napi_throw_error(env, "-11", "napi_create_async_work error");
            return nullptr;
        }
    
        // 11、保存异步任务
        context->work = asyWork;
    
        // 12、添加进异步队列
        napi_queue_async_work(env, asyWork);
    
        return returnValue;
    }
    
    static napi_value GetMd5Sync(napi_env env, napi_callback_info info) {
        // 1、从info中取出JS传递过来的参数放入args
        size_t argc = 1;
        napi_value args[1] = {nullptr};
        if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) {
            napi_throw_error(env, "-1000", "napi_get_cb_info error");
            return nullptr;
        }
    
        // 2、获取参数的类型
        napi_valuetype stringType;
        if (napi_ok != napi_typeof(env, args[0], &stringType)) {
            napi_throw_error(env, "-1001", "napi_typeof error");
            return nullptr;
        }
    
        // 3、如果参数为null或者undefined,则抛异常
        if (napi_null == stringType || napi_undefined == stringType) {
            napi_throw_error(env, "-1002", "the param can't be null");
            return nullptr;
        }
    
        // 4、获取传递的string长度
        size_t length = 0;
        if (napi_ok != napi_get_value_string_utf8(env, args[0], nullptr, 0, &length)) {
            napi_throw_error(env, "-1003", "napi_get_value_string_utf8 error");
            return nullptr;
        }
    
        // 5、如果传递的是"",则抛异常
        if (length == 0) {
            napi_throw_error(env, "-1004", "the param length invalid");
            return nullptr;
        }
    
        // 6、读取传递的string参数放入buffer中
        char *buffer = new char[length + 1];
        if (napi_ok != napi_get_value_string_utf8(env, args[0], buffer, length + 1, &length)) {
            delete[] buffer;
            buffer = nullptr;
            napi_throw_error(env, "-1005", "napi_get_value_string_utf8 error");
            return nullptr;
        }
    
        // 7、计算MD5加密操作
        std::string str = buffer;
        str = MD5(str).toStr();
    
        // 8、把C++数据转成napi_value并返回
        napi_value value = nullptr;
        const char *md5 = str.c_str();
        if (napi_ok != napi_create_string_utf8(env, md5, strlen(md5), &value)) {
            delete[] buffer;
            buffer = nullptr;
            napi_throw_error(env, "-1006", "napi_create_string_utf8 error");
            return nullptr;
        }
    
        // 9、资源清理
        delete[] buffer;
        buffer = nullptr;
    
        return value;
    }
    
    static napi_value Add(napi_env env, napi_callback_info info) {
        size_t requireArgc = 2;
        size_t argc = 2;
        napi_value args[2] = {nullptr};
    
        napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
        napi_valuetype valuetype0;
        napi_typeof(env, args[0], &valuetype0);
    
        napi_valuetype valuetype1;
        napi_typeof(env, args[1], &valuetype1);
    
        double value0;
        napi_get_value_double(env, args[0], &value0);
    
        double value1;
        napi_get_value_double(env, args[1], &value1);
    
        napi_value sum;
        napi_create_double(env, value0 + value1, &sum);
    
        return sum;
    }
    
    EXTERN_C_START
    static napi_value Init(napi_env env, napi_value exports) {
        napi_property_descriptor desc[] = {
            {"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
            {"getMd5Sync", nullptr, GetMd5Sync, nullptr, nullptr, nullptr, napi_default, nullptr},
            {"getMd5", nullptr, GetMd5, nullptr, nullptr, nullptr, napi_default, nullptr},
        };
    
        napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
        return exports;
    }
    EXTERN_C_END
    
    static napi_module demoModule = {
        .nm_version = 1,
        .nm_flags = 0,
        .nm_filename = nullptr,
        .nm_register_func = Init,
        .nm_modname = "entry",
        .nm_priv = ((void *)0),
        .reserved = {0},
    };
    
    extern "C" __attribute__((constructor)) void RegisterEntryModule(void) {
        napi_module_register(&demoModule); 
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332

    Index.ets 的测试代码如下:

    import testNapi from 'libentry.so';
    
    @Entry @Component struct Index {
    
      @State message: string = 'Hello,OpenHarmony'
    
      build() {
        Column({ space: 10 }) {
    
          Text(this.message)
            .fontSize(20)
    
          Button("同步回调")
            .onClick(() => {
              this.message = testNapi.getMd5Sync("Hello, OpenHarmony")
            })
    
          Button("异步 Callback 回调")
            .onClick(() => {
              this.message = "计算中...";
              testNapi.getMd5("Hello, OpenHarmony", (md5: string) => {
                this.message = md5;
              });
            })
    
          Button("异步 Promise 回调")
            .onClick(() => {
              this.message = "计算中...";
              testNapi.getMd5("Hello, OpenHarmony").then((md5: string) => {
                this.message = md5;
              }).catch((error: Error) => {
                this.message = "error: " + error;
              })
            })
        }
        .padding(10)
        .width('100%')
        .height("100%")
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40

    样例运行结果如下图所示:

    16_6_3_1

# 16.6.4:小结

本节笔者简单讲述了 NAPI 的异步实现方式,下一小节笔者从源码的角度给大家讲解一下 NAPI 的实现原理,敬请期待……

请作者喝杯咖啡

津公网安备 12011402001367号

津ICP备2020008934号-2

中央网信办互联网违法和不良信息举报中心

天津市互联网违法和不良信息举报中心