1e41f4b71Sopenharmony_ci# Node-API开发规范 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci## 获取JS传入参数及其数量 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci**【规则】** 当传入napi_get_cb_info的argv不为nullptr时,argv的长度必须大于等于传入argc声明的大小。 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ci当argv不为nullptr时,napi_get_cb_info会根据argc声明的数量将JS实际传入的参数写入argv。如果argc小于等于实际JS传入参数的数量,该接口仅会将声明的argc数量的参数写入argv;而当argc大于实际参数数量时,该接口会在argv的尾部填充undefined。 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci**错误示例** 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ci```cpp 12e41f4b71Sopenharmony_cistatic napi_value IncorrectDemo1(napi_env env, napi_callbackk_info info) { 13e41f4b71Sopenharmony_ci // argc 未正确的初始化,其值为不确定的随机值,导致 argv 的长度可能小于 argc 声明的数量,数据越界。 14e41f4b71Sopenharmony_ci size_t argc; 15e41f4b71Sopenharmony_ci napi_value argv[10] = {nullptr}; 16e41f4b71Sopenharmony_ci napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); 17e41f4b71Sopenharmony_ci return nullptr; 18e41f4b71Sopenharmony_ci} 19e41f4b71Sopenharmony_ci 20e41f4b71Sopenharmony_cistatic napi_value IncorrectDemo2(napi_env env, napi_callback_info info) { 21e41f4b71Sopenharmony_ci // argc 声明的数量大于 argv 实际初始化的长度,导致 napi_get_cb_info 接口在写入 argv 时数据越界。 22e41f4b71Sopenharmony_ci size_t argc = 5; 23e41f4b71Sopenharmony_ci napi_value argv[3] = {nullptr}; 24e41f4b71Sopenharmony_ci napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); 25e41f4b71Sopenharmony_ci return nullptr; 26e41f4b71Sopenharmony_ci} 27e41f4b71Sopenharmony_ci``` 28e41f4b71Sopenharmony_ci 29e41f4b71Sopenharmony_ci**正确示例** 30e41f4b71Sopenharmony_ci 31e41f4b71Sopenharmony_ci```cpp 32e41f4b71Sopenharmony_cistatic napi_value GetArgvDemo1(napi_env env, napi_callback_info info) { 33e41f4b71Sopenharmony_ci size_t argc = 0; 34e41f4b71Sopenharmony_ci // argv 传入 nullptr 来获取传入参数真实数量 35e41f4b71Sopenharmony_ci napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr); 36e41f4b71Sopenharmony_ci // JS 传入参数为0,不执行后续逻辑 37e41f4b71Sopenharmony_ci if (argc == 0) { 38e41f4b71Sopenharmony_ci return nullptr; 39e41f4b71Sopenharmony_ci } 40e41f4b71Sopenharmony_ci // 创建数组用以获取JS传入的参数 41e41f4b71Sopenharmony_ci napi_value* argv = new napi_value[argc]; 42e41f4b71Sopenharmony_ci napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); 43e41f4b71Sopenharmony_ci // 业务代码 44e41f4b71Sopenharmony_ci // ... ... 45e41f4b71Sopenharmony_ci // argv 为 new 创建的对象,在使用完成后手动释放 46e41f4b71Sopenharmony_ci delete argv; 47e41f4b71Sopenharmony_ci return nullptr; 48e41f4b71Sopenharmony_ci} 49e41f4b71Sopenharmony_ci 50e41f4b71Sopenharmony_cistatic napi_value GetArgvDemo2(napi_env env, napi_callback_info info) { 51e41f4b71Sopenharmony_ci size_t argc = 2; 52e41f4b71Sopenharmony_ci napi_value argv[2] = {nullptr}; 53e41f4b71Sopenharmony_ci // napi_get_cb_info 会向 argv 中写入 argc 个 JS 传入参数或 undefined 54e41f4b71Sopenharmony_ci napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); 55e41f4b71Sopenharmony_ci // 业务代码 56e41f4b71Sopenharmony_ci // ... ... 57e41f4b71Sopenharmony_ci return nullptr; 58e41f4b71Sopenharmony_ci} 59e41f4b71Sopenharmony_ci``` 60e41f4b71Sopenharmony_ci 61e41f4b71Sopenharmony_ci## 生命周期管理 62e41f4b71Sopenharmony_ci 63e41f4b71Sopenharmony_ci**【规则】** 合理使用napi_open_handle_scope和napi_close_handle_scope管理napi_value的生命周期,做到生命周期最小化,避免发生内存泄漏问题。 64e41f4b71Sopenharmony_ci 65e41f4b71Sopenharmony_ci每个napi_value属于特定的HandleScope,HandleScope通过napi_open_handle_scope和napi_close_handle_scope来建立和关闭,HandleScope关闭后,所属的napi_value就会自动释放。 66e41f4b71Sopenharmony_ci 67e41f4b71Sopenharmony_ci**正确示例**: 68e41f4b71Sopenharmony_ci 69e41f4b71Sopenharmony_ci```cpp 70e41f4b71Sopenharmony_ci// 在for循环中频繁调用napi接口创建js对象时,要加handle_scope及时释放不再使用的资源。 71e41f4b71Sopenharmony_ci// 下面例子中,每次循环结束局部变量res的生命周期已结束,因此加scope及时释放其持有的js对象,防止内存泄漏 72e41f4b71Sopenharmony_cifor (int i = 0; i < 100000; i++) { 73e41f4b71Sopenharmony_ci napi_handle_scope scope = nullptr; 74e41f4b71Sopenharmony_ci napi_open_handle_scope(env, &scope); 75e41f4b71Sopenharmony_ci if (scope == nullptr) { 76e41f4b71Sopenharmony_ci return; 77e41f4b71Sopenharmony_ci } 78e41f4b71Sopenharmony_ci napi_value res; 79e41f4b71Sopenharmony_ci napi_create_object(env, &res); 80e41f4b71Sopenharmony_ci napi_close_handle_scope(env, scope); 81e41f4b71Sopenharmony_ci} 82e41f4b71Sopenharmony_ci``` 83e41f4b71Sopenharmony_ci 84e41f4b71Sopenharmony_ci## 上下文敏感 85e41f4b71Sopenharmony_ci 86e41f4b71Sopenharmony_ci**【规则】** 多引擎实例场景下,禁止通过Node-API跨引擎实例访问JS对象。 87e41f4b71Sopenharmony_ci 88e41f4b71Sopenharmony_ci引擎实例是一个独立运行环境,JS对象创建访问等操作必须在同一个引擎实例中进行。若在不同引擎实例中操作同一个对象,可能会引发程序崩溃。引擎实例在接口中体现为napi_env。 89e41f4b71Sopenharmony_ci 90e41f4b71Sopenharmony_ci**错误示例**: 91e41f4b71Sopenharmony_ci 92e41f4b71Sopenharmony_ci```cpp 93e41f4b71Sopenharmony_ci// 线程1执行,在env1创建string对象,值为"bar"、 94e41f4b71Sopenharmony_cinapi_create_string_utf8(env1, "bar", NAPI_AUTO_LENGTH, &string); 95e41f4b71Sopenharmony_ci// 线程2执行,在env2创建object对象,并将上述的string对象设置到object对象中 96e41f4b71Sopenharmony_cinapi_status status = napi_create_object(env2, &object); 97e41f4b71Sopenharmony_ciif (status != napi_ok) { 98e41f4b71Sopenharmony_ci napi_throw_error(env, ...); 99e41f4b71Sopenharmony_ci return; 100e41f4b71Sopenharmony_ci} 101e41f4b71Sopenharmony_ci 102e41f4b71Sopenharmony_cistatus = napi_set_named_property(env2, object, "foo", string); 103e41f4b71Sopenharmony_ciif (status != napi_ok) { 104e41f4b71Sopenharmony_ci napi_throw_error(env, ...); 105e41f4b71Sopenharmony_ci return; 106e41f4b71Sopenharmony_ci} 107e41f4b71Sopenharmony_ci``` 108e41f4b71Sopenharmony_ci 109e41f4b71Sopenharmony_ci所有的JS对象都隶属于具体的某一napi_env,不可将env1的对象,设置到env2中的对象中。在env2中一旦访问到env1的对象,程序可能会发生崩溃。 110e41f4b71Sopenharmony_ci 111e41f4b71Sopenharmony_ci## 异常处理 112e41f4b71Sopenharmony_ci 113e41f4b71Sopenharmony_ci**【建议】** Node-API接口调用发生异常需要及时处理,不能遗漏异常到后续逻辑,否则程序可能发生不可预期行为。 114e41f4b71Sopenharmony_ci 115e41f4b71Sopenharmony_ci**正确示例**: 116e41f4b71Sopenharmony_ci 117e41f4b71Sopenharmony_ci```cpp 118e41f4b71Sopenharmony_ci// 1.创建对象 119e41f4b71Sopenharmony_cinapi_status status = napi_create_object(env, &object); 120e41f4b71Sopenharmony_ciif (status != napi_ok) { 121e41f4b71Sopenharmony_ci napi_throw_error(env, ...); 122e41f4b71Sopenharmony_ci return; 123e41f4b71Sopenharmony_ci} 124e41f4b71Sopenharmony_ci// 2.创建属性值 125e41f4b71Sopenharmony_cistatus = napi_create_string_utf8(env, "bar", NAPI_AUTO_LENGTH, &string); 126e41f4b71Sopenharmony_ciif (status != napi_ok) { 127e41f4b71Sopenharmony_ci napi_throw_error(env, ...); 128e41f4b71Sopenharmony_ci return; 129e41f4b71Sopenharmony_ci} 130e41f4b71Sopenharmony_ci// 3.将步骤2的结果设置为对象object属性foo的值 131e41f4b71Sopenharmony_cistatus = napi_set_named_property(env, object, "foo", string); 132e41f4b71Sopenharmony_ciif (status != napi_ok) { 133e41f4b71Sopenharmony_ci napi_throw_error(env, ...); 134e41f4b71Sopenharmony_ci return; 135e41f4b71Sopenharmony_ci} 136e41f4b71Sopenharmony_ci``` 137e41f4b71Sopenharmony_ci 138e41f4b71Sopenharmony_ci如上示例中,步骤1或者步骤2出现异常时,步骤3都不会正常进行。只有当方法的返回值是napi_ok时,才能保持继续正常运行;否则后续流程可能会出现不可预期的行为。 139e41f4b71Sopenharmony_ci 140e41f4b71Sopenharmony_ci## 异步任务 141e41f4b71Sopenharmony_ci 142e41f4b71Sopenharmony_ci**【规则】** 当使用uv_queue_work方法将任务抛到JS线程上面执行的时候,对JS线程的回调方法,一般情况下需要加上napi_handle_scope来管理回调方法创建的napi_value的生命周期。 143e41f4b71Sopenharmony_ci 144e41f4b71Sopenharmony_ci使用uv_queue_work方法,不会走Node-API框架,此时需要开发者自己合理使用napi_handle_scope来管理napi_value的生命周期。 145e41f4b71Sopenharmony_ci 146e41f4b71Sopenharmony_ci**正确示例**: 147e41f4b71Sopenharmony_ci 148e41f4b71Sopenharmony_ci```cpp 149e41f4b71Sopenharmony_civoid callbackTest(CallbackContext* context) 150e41f4b71Sopenharmony_ci{ 151e41f4b71Sopenharmony_ci uv_loop_s* loop = nullptr; 152e41f4b71Sopenharmony_ci napi_get_uv_event_loop(context->env, &loop); 153e41f4b71Sopenharmony_ci uv_work_t* work = new uv_work_t; 154e41f4b71Sopenharmony_ci context->retData = 1; 155e41f4b71Sopenharmony_ci work->data = (void*)context; 156e41f4b71Sopenharmony_ci uv_queue_work( 157e41f4b71Sopenharmony_ci loop, work, [](uv_work_t* work) {}, 158e41f4b71Sopenharmony_ci // using callback function back to JS thread 159e41f4b71Sopenharmony_ci [](uv_work_t* work, int status) { 160e41f4b71Sopenharmony_ci CallbackContext* context = (CallbackContext*)work->data; 161e41f4b71Sopenharmony_ci napi_handle_scope scope = nullptr; 162e41f4b71Sopenharmony_ci napi_open_handle_scope(context->env, &scope); 163e41f4b71Sopenharmony_ci if (scope == nullptr) { 164e41f4b71Sopenharmony_ci if (work != nullptr) { 165e41f4b71Sopenharmony_ci delete work; 166e41f4b71Sopenharmony_ci } 167e41f4b71Sopenharmony_ci return; 168e41f4b71Sopenharmony_ci } 169e41f4b71Sopenharmony_ci napi_value callback = nullptr; 170e41f4b71Sopenharmony_ci napi_get_reference_value(context->env, context->callbackRef, &callback); 171e41f4b71Sopenharmony_ci napi_value retArg; 172e41f4b71Sopenharmony_ci napi_create_int32(context->env, context->retData, &retArg); 173e41f4b71Sopenharmony_ci napi_value ret; 174e41f4b71Sopenharmony_ci napi_call_function(context->env, nullptr, callback, 1, &retArg, &ret); 175e41f4b71Sopenharmony_ci napi_delete_reference(context->env, context->callbackRef); 176e41f4b71Sopenharmony_ci napi_close_handle_scope(context->env, scope); 177e41f4b71Sopenharmony_ci if (work != nullptr) { 178e41f4b71Sopenharmony_ci delete work; 179e41f4b71Sopenharmony_ci } 180e41f4b71Sopenharmony_ci delete context; 181e41f4b71Sopenharmony_ci } 182e41f4b71Sopenharmony_ci ); 183e41f4b71Sopenharmony_ci} 184e41f4b71Sopenharmony_ci``` 185e41f4b71Sopenharmony_ci 186e41f4b71Sopenharmony_ci## 对象绑定 187e41f4b71Sopenharmony_ci 188e41f4b71Sopenharmony_ci**【规则】** 使用napi_wrap接口,如果最后一个参数result传递不为nullptr,需要开发者在合适的时机调用napi_remove_wrap函数主动删除创建的napi_ref。 189e41f4b71Sopenharmony_ci 190e41f4b71Sopenharmony_cinapi_wrap接口定义如下: 191e41f4b71Sopenharmony_ci 192e41f4b71Sopenharmony_ci```cpp 193e41f4b71Sopenharmony_cinapi_wrap(napi_env env, napi_value js_object, void* native_object, napi_finalize finalize_cb, void* finalize_hint, napi_ref* result) 194e41f4b71Sopenharmony_ci``` 195e41f4b71Sopenharmony_ci 196e41f4b71Sopenharmony_ci当最后一个参数result不为空时,框架会创建一个napi_ref对象,指向js_object。此时开发者需要自己管理js_object的生命周期,即需要在合适的时机调用napi_remove_wrap删除napi_ref,这样GC才能正常释放js_object,从而触发绑定C++对象native_object的析构函数finalize_cb。 197e41f4b71Sopenharmony_ci 198e41f4b71Sopenharmony_ci一般情况下,根据业务情况最后一个参数result可以直接传递为nullptr。 199e41f4b71Sopenharmony_ci 200e41f4b71Sopenharmony_ci**正确示例**: 201e41f4b71Sopenharmony_ci 202e41f4b71Sopenharmony_ci```cpp 203e41f4b71Sopenharmony_ci// 用法1:napi_wrap不需要接收创建的napi_ref,最后一个参数传递nullptr,创建的napi_ref是弱引用,由系统管理,不需要用户手动释放 204e41f4b71Sopenharmony_cinapi_wrap(env, jsobject, nativeObject, cb, nullptr, nullptr); 205e41f4b71Sopenharmony_ci 206e41f4b71Sopenharmony_ci// 用法2:napi_wrap需要接收创建的napi_ref,最后一个参数不为nullptr,返回的napi_ref是强引用,需要用户手动释放,否则会内存泄漏 207e41f4b71Sopenharmony_cinapi_ref result; 208e41f4b71Sopenharmony_cinapi_wrap(env, jsobject, nativeObject, cb, nullptr, &result); 209e41f4b71Sopenharmony_ci// 当js_object和result后续不再使用时,及时调用napi_remove_wrap释放result 210e41f4b71Sopenharmony_civoid* nativeObjectResult = nullptr; 211e41f4b71Sopenharmony_cinapi_remove_wrap(env, jsobject, &nativeObjectResult); 212e41f4b71Sopenharmony_ci``` 213e41f4b71Sopenharmony_ci 214e41f4b71Sopenharmony_ci## 高性能数组 215e41f4b71Sopenharmony_ci 216e41f4b71Sopenharmony_ci**【建议】** 存储值类型数据时,使用ArrayBuffer代替JSArray来提高应用性能。 217e41f4b71Sopenharmony_ci 218e41f4b71Sopenharmony_ci使用JSArray作为容器储存数据,支持几乎所有的JS数据类型。 219e41f4b71Sopenharmony_ci 220e41f4b71Sopenharmony_ci使用napi_set_element方法对JSArray存储值类型数据(如int32)时,同样会涉及到与运行时的交互,造成不必要的开销。 221e41f4b71Sopenharmony_ci 222e41f4b71Sopenharmony_ciArrayBuffer进行增改是直接对缓冲区进行更改,具有远优于使用napi_set_element操作JSArray的性能表现。 223e41f4b71Sopenharmony_ci 224e41f4b71Sopenharmony_ci因此此种场景下,更推荐使用napi_create_arraybuffer接口创建的ArrayBuffer对象。 225e41f4b71Sopenharmony_ci 226e41f4b71Sopenharmony_ci**示例:** 227e41f4b71Sopenharmony_ci 228e41f4b71Sopenharmony_ci```cpp 229e41f4b71Sopenharmony_ci// 以下代码使用常规JSArray作为容器,但其仅存储int32类型数据。 230e41f4b71Sopenharmony_ci// 但因为是JS对象,因此只能使用napi方法对其进行增改,性能较低。 231e41f4b71Sopenharmony_cistatic napi_value ArrayDemo(napi_env env, napi_callback_info info) 232e41f4b71Sopenharmony_ci{ 233e41f4b71Sopenharmony_ci constexpr size_t arrSize = 1000; 234e41f4b71Sopenharmony_ci napi_value jsArr = nullptr; 235e41f4b71Sopenharmony_ci napi_create_array(env, &jsArr); 236e41f4b71Sopenharmony_ci for (int i = 0; i < arrSize; i++) { 237e41f4b71Sopenharmony_ci napi_value arrValue = nullptr; 238e41f4b71Sopenharmony_ci napi_create_int32(env, i, &arrValue); 239e41f4b71Sopenharmony_ci // 常规JSArray使用napi方法对array进行读写,性能较差。 240e41f4b71Sopenharmony_ci napi_set_element(env, jsArr, i, arrValue); 241e41f4b71Sopenharmony_ci } 242e41f4b71Sopenharmony_ci return jsArr; 243e41f4b71Sopenharmony_ci} 244e41f4b71Sopenharmony_ci 245e41f4b71Sopenharmony_ci// 推荐写法: 246e41f4b71Sopenharmony_ci// 同样以int32类型数据为例,但以下代码使用ArrayBuffer作为容器。 247e41f4b71Sopenharmony_ci// 因此可以使用C/C++的方法直接对缓冲区进行增改。 248e41f4b71Sopenharmony_cistatic napi_value ArrayBufferDemo(napi_env env, napi_callback_info info) 249e41f4b71Sopenharmony_ci{ 250e41f4b71Sopenharmony_ci constexpr size_t arrSize = 1000; 251e41f4b71Sopenharmony_ci napi_value arrBuffer = nullptr; 252e41f4b71Sopenharmony_ci void* data = nullptr; 253e41f4b71Sopenharmony_ci 254e41f4b71Sopenharmony_ci napi_create_arraybuffer(env, arrSize * sizeof(int32_t), &data, &arrBuffer); 255e41f4b71Sopenharmony_ci int32_t* i32Buffer = reinterpret_cast<int32_t*>(data); 256e41f4b71Sopenharmony_ci for (int i = 0; i < arrSize; i++) { 257e41f4b71Sopenharmony_ci // arrayBuffer直接对缓冲区进行修改,跳过运行时, 258e41f4b71Sopenharmony_ci // 与操作原生C/C++对象性能相当 259e41f4b71Sopenharmony_ci i32Buffer[i] = i; 260e41f4b71Sopenharmony_ci } 261e41f4b71Sopenharmony_ci 262e41f4b71Sopenharmony_ci return arrBuffer; 263e41f4b71Sopenharmony_ci} 264e41f4b71Sopenharmony_ci``` 265e41f4b71Sopenharmony_ci 266e41f4b71Sopenharmony_cinapi_create_arraybuffer等同于JS代码中的`new ArrayBuffer(size)`,其生成的对象不可直接在TS/JS中进行读取,需要将其包装为TyppedArray或DataView后方可进行读写。 267e41f4b71Sopenharmony_ci 268e41f4b71Sopenharmony_ci**基准性能测试结果如下:** 269e41f4b71Sopenharmony_ci 270e41f4b71Sopenharmony_ci> **说明:** 271e41f4b71Sopenharmony_ci> 272e41f4b71Sopenharmony_ci> 以下数据为千次循环写入累计数据,为更好的体现出差异,已对设备核心频率进行限制。 273e41f4b71Sopenharmony_ci 274e41f4b71Sopenharmony_ci| 容器类型 | Benchmark数据(us) | 275e41f4b71Sopenharmony_ci| ----------- | ------------------- | 276e41f4b71Sopenharmony_ci| JSArray | 1566.174 | 277e41f4b71Sopenharmony_ci| ArrayBuffer | 3.609 | 278e41f4b71Sopenharmony_ci 279e41f4b71Sopenharmony_ci## 数据转换 280e41f4b71Sopenharmony_ci 281e41f4b71Sopenharmony_ci**【建议】** 尽可能的减少数据转换次数,避免不必要的复制。 282e41f4b71Sopenharmony_ci 283e41f4b71Sopenharmony_ci- **减少数据转换次数:** 频繁的数据转换可能会导致性能下降,可以通过批量处理数据或者使用更高效的数据结构来优化性能。 284e41f4b71Sopenharmony_ci- **避免不必要的数据复制:** 在进行数据转换时,可以使用Node-API提供的接口来直接访问原始数据,而不是创建新的副本。 285e41f4b71Sopenharmony_ci- **使用缓存:** 如果某些数据在多次转换中都会被使用到,可以考虑使用缓存来避免重复的数据转换。缓存可以减少不必要的计算,提高性能。 286e41f4b71Sopenharmony_ci 287e41f4b71Sopenharmony_ci## 模块注册与模块命名 288e41f4b71Sopenharmony_ci 289e41f4b71Sopenharmony_ci**【规则】** 290e41f4b71Sopenharmony_cinm_register_func对应的函数需要加上修饰符static,防止与其他so里的符号冲突。 291e41f4b71Sopenharmony_ci 292e41f4b71Sopenharmony_ci模块注册的入口,即使用__attribute__((constructor))修饰函数的函数名需要确保与其他模块不同。 293e41f4b71Sopenharmony_ci 294e41f4b71Sopenharmony_ci模块实现中.nm_modname字段需要与模块名完全匹配,区分大小写。 295e41f4b71Sopenharmony_ci 296e41f4b71Sopenharmony_ci**错误示例** 297e41f4b71Sopenharmony_ci以下代码为模块名为nativerender时的错误示例 298e41f4b71Sopenharmony_ci 299e41f4b71Sopenharmony_ci```cpp 300e41f4b71Sopenharmony_ciEXTERN_C_START 301e41f4b71Sopenharmony_cinapi_value Init(napi_env env, napi_value exports) 302e41f4b71Sopenharmony_ci{ 303e41f4b71Sopenharmony_ci // ... 304e41f4b71Sopenharmony_ci return exports; 305e41f4b71Sopenharmony_ci} 306e41f4b71Sopenharmony_ciEXTERN_C_END 307e41f4b71Sopenharmony_ci 308e41f4b71Sopenharmony_cistatic napi_module nativeModule = { 309e41f4b71Sopenharmony_ci .nm_version = 1, 310e41f4b71Sopenharmony_ci .nm_flags = 0, 311e41f4b71Sopenharmony_ci .nm_filename = nullptr, 312e41f4b71Sopenharmony_ci //没有在nm_register_func对应的函数加上static 313e41f4b71Sopenharmony_ci .nm_register_func = Init, 314e41f4b71Sopenharmony_ci // 模块实现中.nm_modname字段没有与模块名完全匹配,会导致多线程场景模块加载失败 315e41f4b71Sopenharmony_ci .nm_modname = "entry", 316e41f4b71Sopenharmony_ci .nm_priv = nullptr, 317e41f4b71Sopenharmony_ci .reserved = { 0 }, 318e41f4b71Sopenharmony_ci}; 319e41f4b71Sopenharmony_ci 320e41f4b71Sopenharmony_ci//模块注册的入口函数名为RegisterModule,容易与其他模块重复。 321e41f4b71Sopenharmony_ciextern "C" __attribute__((constructor)) void RegisterModule() 322e41f4b71Sopenharmony_ci{ 323e41f4b71Sopenharmony_ci napi_module_register(&nativeModule); 324e41f4b71Sopenharmony_ci} 325e41f4b71Sopenharmony_ci``` 326e41f4b71Sopenharmony_ci 327e41f4b71Sopenharmony_ci**正确示例**: 328e41f4b71Sopenharmony_ci以下代码为模块名为nativerender时的正确示例 329e41f4b71Sopenharmony_ci 330e41f4b71Sopenharmony_ci```cpp 331e41f4b71Sopenharmony_ciEXTERN_C_START 332e41f4b71Sopenharmony_cistatic napi_value Init(napi_env env, napi_value exports) 333e41f4b71Sopenharmony_ci{ 334e41f4b71Sopenharmony_ci // ... 335e41f4b71Sopenharmony_ci return exports; 336e41f4b71Sopenharmony_ci} 337e41f4b71Sopenharmony_ciEXTERN_C_END 338e41f4b71Sopenharmony_ci 339e41f4b71Sopenharmony_cistatic napi_module nativeModule = { 340e41f4b71Sopenharmony_ci .nm_version = 1, 341e41f4b71Sopenharmony_ci .nm_flags = 0, 342e41f4b71Sopenharmony_ci .nm_filename = nullptr, 343e41f4b71Sopenharmony_ci .nm_register_func = Init, 344e41f4b71Sopenharmony_ci .nm_modname = "nativerender", 345e41f4b71Sopenharmony_ci .nm_priv = nullptr, 346e41f4b71Sopenharmony_ci .reserved = { 0 }, 347e41f4b71Sopenharmony_ci}; 348e41f4b71Sopenharmony_ci 349e41f4b71Sopenharmony_ciextern "C" __attribute__((constructor)) void RegisterNativeRenderModule() 350e41f4b71Sopenharmony_ci{ 351e41f4b71Sopenharmony_ci napi_module_register(&nativeModule); 352e41f4b71Sopenharmony_ci} 353e41f4b71Sopenharmony_ci``` 354e41f4b71Sopenharmony_ci 355e41f4b71Sopenharmony_ci## 正确的使用napi_create_external系列接口创建的JS Object 356e41f4b71Sopenharmony_ci 357e41f4b71Sopenharmony_ci**【规则】** napi_create_external系列接口创建出来的JS对象仅允许在当前线程传递和使用,跨线程传递(如使用worker的post_message)将会导致应用crash。若需跨线程传递绑定有Native对象的JS对象,请使用napi_coerce_to_native_binding_object接口绑定JS对象和Native对象。 358e41f4b71Sopenharmony_ci 359e41f4b71Sopenharmony_ci**错误示例** 360e41f4b71Sopenharmony_ci 361e41f4b71Sopenharmony_ci```cpp 362e41f4b71Sopenharmony_cistatic void MyFinalizeCB(napi_env env, void *finalize_data, void *finalize_hint) { return; }; 363e41f4b71Sopenharmony_ci 364e41f4b71Sopenharmony_cistatic napi_value CreateMyExternal(napi_env env, napi_callback_info info) { 365e41f4b71Sopenharmony_ci napi_value result = nullptr; 366e41f4b71Sopenharmony_ci napi_create_external(env, nullptr, MyFinalizeCB, nullptr, &result); 367e41f4b71Sopenharmony_ci return result; 368e41f4b71Sopenharmony_ci} 369e41f4b71Sopenharmony_ci 370e41f4b71Sopenharmony_ci// 此处已省略模块注册的代码, 你可能需要自行注册 CreateMyExternal 方法 371e41f4b71Sopenharmony_ci``` 372e41f4b71Sopenharmony_ci 373e41f4b71Sopenharmony_ci```ts 374e41f4b71Sopenharmony_ci// index.d.ts 375e41f4b71Sopenharmony_ciexport const createMyExternal: () => Object; 376e41f4b71Sopenharmony_ci 377e41f4b71Sopenharmony_ci// 应用代码 378e41f4b71Sopenharmony_ciimport testNapi from 'libentry.so'; 379e41f4b71Sopenharmony_ciimport worker from '@ohos.worker'; 380e41f4b71Sopenharmony_ci 381e41f4b71Sopenharmony_ciconst mWorker = new worker.ThreadWorker('../workers/Worker'); 382e41f4b71Sopenharmony_ci 383e41f4b71Sopenharmony_ci{ 384e41f4b71Sopenharmony_ci const mExternalObj = testNapi.createMyExternal(); 385e41f4b71Sopenharmony_ci 386e41f4b71Sopenharmony_ci mWorker.postMessage(mExternalObj); 387e41f4b71Sopenharmony_ci 388e41f4b71Sopenharmony_ci} 389e41f4b71Sopenharmony_ci 390e41f4b71Sopenharmony_ci// 关闭worker线程 391e41f4b71Sopenharmony_ci// 应用可能在此步骤崩溃, 或在后续引擎进行GC的时候崩溃 392e41f4b71Sopenharmony_cimWorker.terminate(); 393e41f4b71Sopenharmony_ci// Worker的实现为默认模板,此处省略 394e41f4b71Sopenharmony_ci``` 395e41f4b71Sopenharmony_ci 396e41f4b71Sopenharmony_ci## 其它 397e41f4b71Sopenharmony_ci 398e41f4b71Sopenharmony_ci**【规则】** 使用napi_get_arraybuffer_info接口,第三个参数data资源开发者不允许释放,data的生命周期受引擎管理。 399e41f4b71Sopenharmony_ci 400e41f4b71Sopenharmony_cinapi_get_arraybuffer_info接口定义如下: 401e41f4b71Sopenharmony_ci 402e41f4b71Sopenharmony_ci```cpp 403e41f4b71Sopenharmony_cinapi_get_arraybuffer_info(napi_env env, napi_value arraybuffer, void** data, size_t* byte_length) 404e41f4b71Sopenharmony_ci``` 405e41f4b71Sopenharmony_ci 406e41f4b71Sopenharmony_cidata获取的是ArrayBuffer的Buffer头指针,开发者只可以在范围内读写该Buffer区域,不可以进行释放操作。该段内存由引擎内部的ArrayBuffer Allocator管理,随JS对象ArrayBuffer的生命周期释放。 407e41f4b71Sopenharmony_ci 408e41f4b71Sopenharmony_ci**错误示例:** 409e41f4b71Sopenharmony_ci 410e41f4b71Sopenharmony_ci```cpp 411e41f4b71Sopenharmony_civoid* arrayBufferPtr = nullptr; 412e41f4b71Sopenharmony_cinapi_value arrayBuffer = nullptr; 413e41f4b71Sopenharmony_cisize_t createBufferSize = ARRAY_BUFFER_SIZE; 414e41f4b71Sopenharmony_cinapi_status verification = napi_create_arraybuffer(env, createBufferSize, &arrayBufferPtr, &arrayBuffer); 415e41f4b71Sopenharmony_cisize_t arrayBufferSize; 416e41f4b71Sopenharmony_cinapi_status result = napi_get_arraybuffer_info(env, arrayBuffer, &arrayBufferPtr, &arrayBufferSize); 417e41f4b71Sopenharmony_cidelete arrayBufferPtr; // 这一步是禁止的,创建的arrayBufferPtr生命周期由引擎管理,不允许用户自己delete,否则会double free 418e41f4b71Sopenharmony_ci``` 419e41f4b71Sopenharmony_ci 420e41f4b71Sopenharmony_ci**【建议】** 合理使用napi_object_freeze和napi_object_seal来控制对象以及对象属性的可变性。 421e41f4b71Sopenharmony_ci 422e41f4b71Sopenharmony_cinapi_object_freeze等同于Object.freeze语义,freeze后对象的所有属性都不可能以任何方式被修改;napi_object_seal等同于Object.seal语义,对象不可增删属性。两者的主要区别是,freeze不能改属性的值,seal还可以改属性的值。 423e41f4b71Sopenharmony_ci 424e41f4b71Sopenharmony_ci开发者使用以上语义时,需确保约束条件是自己需要的,一旦违背以上语义严格模式下就会抛出Error(默认严格模式)。 425