1e41f4b71Sopenharmony_ci# Node-API Development Specifications 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci## Obtaining Arguments Passed by JS 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci**[Rule]** When **argv** in **napi_get_cb_info** is not **nullptr**, the length of **argv** must be greater than or equal to **argc**. 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ciIf **argv** is not **nullptr**, the arguments actually passed by JS will be copied to **argv** in **napi_get_cb_info** based on the value of **argc**. If there are more arguments than the provided count, only the requested number of arguments are copied. If there are fewer arguments provided than the claimed, the rest of **argv** is filled with values that represent **undefined**. 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci**Example (incorrect)** 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ci```cpp 12e41f4b71Sopenharmony_cistatic napi_value IncorrectDemo1(napi_env env, napi_callbackk_info info) { 13e41f4b71Sopenharmony_ci // argc is not correctly initialized and is set to a random value. If the length of argv is less than the number of arguments specified by argc, data overwriting occurs. 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 // The number of arguments specified by argc is greater than the length of argv. As a result, data overwriting occurs when napi_get_cb_info writes 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**Example (correct)** 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 // Pass in nullptr to argv to obtain the actual number of arguments passed by JS. 35e41f4b71Sopenharmony_ci napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr); 36e41f4b71Sopenharmony_ci // If 0 is passed by JS, the subsequent logic is not executed. 37e41f4b71Sopenharmony_ci if (argc == 0) { 38e41f4b71Sopenharmony_ci return nullptr; 39e41f4b71Sopenharmony_ci } 40e41f4b71Sopenharmony_ci // Create an array to obtain the arguments passed by JS. 41e41f4b71Sopenharmony_ci napi_value* argv = new napi_value[argc]; 42e41f4b71Sopenharmony_ci napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); 43e41f4b71Sopenharmony_ci // Service code. 44e41f4b71Sopenharmony_ci // ... ... 45e41f4b71Sopenharmony_ci // argv is an object created by new and must be manually released when it is not required. 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 writes the arguments (of the quantity specified by argc) passed by JS or undefined to argv. 54e41f4b71Sopenharmony_ci napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr); 55e41f4b71Sopenharmony_ci // Service code. 56e41f4b71Sopenharmony_ci // ... ... 57e41f4b71Sopenharmony_ci return nullptr; 58e41f4b71Sopenharmony_ci} 59e41f4b71Sopenharmony_ci``` 60e41f4b71Sopenharmony_ci 61e41f4b71Sopenharmony_ci## Lifecycle Management 62e41f4b71Sopenharmony_ci 63e41f4b71Sopenharmony_ci**[Rule]** Properly use **napi_open_handle_scope** and **napi_close_handle_scope** to minimize the lifecycle of **napi_value** and avoid memory leakage. 64e41f4b71Sopenharmony_ci 65e41f4b71Sopenharmony_ciEach **napi_value** belongs to a specific **HandleScope**, which is opened and closed by **napi_open_handle_scope** and **napi_close_handle_scope**, respectively. After a **HandleScope** is closed, its **napi_value** is automatically released. 66e41f4b71Sopenharmony_ci 67e41f4b71Sopenharmony_ci**Example (correct)** 68e41f4b71Sopenharmony_ci 69e41f4b71Sopenharmony_ci```cpp 70e41f4b71Sopenharmony_ci// When Node-API is frequently called to create JS objects in the for loop, use handle_scope to release resources in a timely manner when they are no longer used. 71e41f4b71Sopenharmony_ci// In the following example, the lifecycle of the local variable res ends at the end of each loop. To prevent memory leaks, scope is used to release the JS object in a timely manner. 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## Context Sensitive 85e41f4b71Sopenharmony_ci 86e41f4b71Sopenharmony_ci**[Rule]** Do not use Node-API to access JS objects across engine instances. 87e41f4b71Sopenharmony_ci 88e41f4b71Sopenharmony_ciAn engine instance is an independent running environment. Operations such as creating and accessing a JS object must be performed in the same engine instance. If an object is operated in different engine instances, the application may crash. An engine instance is represented as a value of **napi_env** in APIs. 89e41f4b71Sopenharmony_ci 90e41f4b71Sopenharmony_ci**Example (incorrect)** 91e41f4b71Sopenharmony_ci 92e41f4b71Sopenharmony_ci```cpp 93e41f4b71Sopenharmony_ci// Create a string object with value of "bar" in env1. 94e41f4b71Sopenharmony_cinapi_create_string_utf8(env1, "bar", NAPI_AUTO_LENGTH, &string); 95e41f4b71Sopenharmony_ci// Create an object in env2 and set the string object to this 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_ciJS objects belong to a specific **napi_env**. Therefore, you cannot set an object of env1 to an object of env2. If the object of env1 is accessed in env2, the application may crash. 110e41f4b71Sopenharmony_ci 111e41f4b71Sopenharmony_ci## Exception Handling 112e41f4b71Sopenharmony_ci 113e41f4b71Sopenharmony_ci**[Suggestion]** Any exception occurred in a Node-API call should be handled in a timely manner. Otherwise, unexpected behavior may occur. 114e41f4b71Sopenharmony_ci 115e41f4b71Sopenharmony_ci**Example (correct)** 116e41f4b71Sopenharmony_ci 117e41f4b71Sopenharmony_ci```cpp 118e41f4b71Sopenharmony_ci// 1. Create an object. 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. Create a property. 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. Set the result of step 2 to the value of the object property 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_ciIn this example, if an exception occurs in step 1 or step 2, step 3 will not be performed. Step 3 will be performed only when napi_ok is returned in steps 1 and 2. 139e41f4b71Sopenharmony_ci 140e41f4b71Sopenharmony_ci## Asynchronous Tasks 141e41f4b71Sopenharmony_ci 142e41f4b71Sopenharmony_ci**[Rule]** When the **uv_queue_work** method is called to throw a work to a JS thread for execution, use **napi_handle_scope** to manage the lifecycle of **napi_value** created by the JS callback. 143e41f4b71Sopenharmony_ci 144e41f4b71Sopenharmony_ciThe Node-API framework will not be used when the **uv_queue_work** method is called. In this case, you must use **napi_handle_scope** to manage the lifecycle of **napi_value**. 145e41f4b71Sopenharmony_ci 146e41f4b71Sopenharmony_ci**Example (correct)** 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## Object Wrapping 187e41f4b71Sopenharmony_ci 188e41f4b71Sopenharmony_ci**[Rule]** If the value of the last parameter **result** is not **nullptr** in **napi_wrap()**, use **napi_remove_wrap()** at a proper time to delete the created **napi_ref**. 189e41f4b71Sopenharmony_ci 190e41f4b71Sopenharmony_ciThe **napi_wrap** interface is defined as follows: 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_ciWhen the last parameter **result** is not null, the Node-API framework creates an **napi_ref** object pointing to **js_object**. You need to manage the lifecycle of **js_object**. Specifically, use **napi_remove_wrap** to delete **napi_ref** at a proper time so that the garbage collector (GC) can release **js_object** and trigger the destructor **finalize_cb** bound to the C++ object **native_object**. 197e41f4b71Sopenharmony_ci 198e41f4b71Sopenharmony_ciGenerally, you can directly pass in **nullptr** for the last parameter **result**. 199e41f4b71Sopenharmony_ci 200e41f4b71Sopenharmony_ci**Example (correct)** 201e41f4b71Sopenharmony_ci 202e41f4b71Sopenharmony_ci```cpp 203e41f4b71Sopenharmony_ci// Case 1: Pass in nullptr via the last parameter in napi_wrap. In this case, the created napi_ref is a weak reference, which is managed by the system and does not need manual release. 204e41f4b71Sopenharmony_cinapi_wrap(env, jsobject, nativeObject, cb, nullptr, nullptr); 205e41f4b71Sopenharmony_ci 206e41f4b71Sopenharmony_ci// Case 2: The last parameter in napi_wrap is not nullptr. In this case, the returned napi_ref is a strong reference and needs to be manually released. Otherwise, memory leakage may occur. 207e41f4b71Sopenharmony_cinapi_ref result; 208e41f4b71Sopenharmony_cinapi_wrap(env, jsobject, nativeObject, cb, nullptr, &result); 209e41f4b71Sopenharmony_ci// When js_object and result are no longer used, call napi_remove_wrap to release result. 210e41f4b71Sopenharmony_civoid* nativeObjectResult = nullptr; 211e41f4b71Sopenharmony_cinapi_remove_wrap(env, jsobject, &nativeObjectResult); 212e41f4b71Sopenharmony_ci``` 213e41f4b71Sopenharmony_ci 214e41f4b71Sopenharmony_ci## Arrays for High Performance 215e41f4b71Sopenharmony_ci 216e41f4b71Sopenharmony_ci**[Suggestion]** Use ArrayBuffer instead of JSArray to store value-type data for higher performance. 217e41f4b71Sopenharmony_ci 218e41f4b71Sopenharmony_ciJSArray is used as a container to store data and supports almost all JS data types. 219e41f4b71Sopenharmony_ci 220e41f4b71Sopenharmony_ciWhen **napi_set_element** is used to store value-type data (such as int32) in JSArray, interaction with the runtime is involved, which causes unnecessary overhead. 221e41f4b71Sopenharmony_ci 222e41f4b71Sopenharmony_ciThe operations on ArrayBuffer are performed in the buffer, which delivers higher performance than using **napi_set_element** to operate JSArray. 223e41f4b71Sopenharmony_ci 224e41f4b71Sopenharmony_ciTherefore, you are advised to use the **ArrayBuffer** object created by **napi_create_arraybuffer** in this scenario. 225e41f4b71Sopenharmony_ci 226e41f4b71Sopenharmony_ci**Example:** 227e41f4b71Sopenharmony_ci 228e41f4b71Sopenharmony_ci```cpp 229e41f4b71Sopenharmony_ci// In the following code, JSArray is used to store only int32 data. 230e41f4b71Sopenharmony_ci// Since JSArray is a JS object, only Node-API methods can be used to operate it, which compromises the performance. 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 // Using Node-API methods to read and write JSArray affects the performance. 240e41f4b71Sopenharmony_ci napi_set_element(env, jsArr, i, arrValue); 241e41f4b71Sopenharmony_ci } 242e41f4b71Sopenharmony_ci return jsArr; 243e41f4b71Sopenharmony_ci} 244e41f4b71Sopenharmony_ci 245e41f4b71Sopenharmony_ci// To improve the performance, modify the code as follows: 246e41f4b71Sopenharmony_ci// Use ArrayBuffer to hold int32 data. 247e41f4b71Sopenharmony_ci// In this case, C/C++ methods can be used to directly add or modify data in the buffer. 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 // Using arrayBuffer allows data to be directly modified in the buffer, which eliminates the interaction with the runtime. 258e41f4b71Sopenharmony_ci // The performance is equivalent to that of operating native C/C++ objects. 259e41f4b71Sopenharmony_ci i32Buffer[i] = i; 260e41f4b71Sopenharmony_ci } 261e41f4b71Sopenharmony_ci 262e41f4b71Sopenharmony_ci return arrBuffer; 263e41f4b71Sopenharmony_ci} 264e41f4b71Sopenharmony_ci``` 265e41f4b71Sopenharmony_ci 266e41f4b71Sopenharmony_ci**napi_create_arraybuffer** is equivalent to **new ArrayBuffer(size)** in JS. The object generated cannot be directly read in TS/JS. It can be read or written only after being encapsulated into a TyppedArray or DataView object. 267e41f4b71Sopenharmony_ci 268e41f4b71Sopenharmony_ci**Benchmark performance test result**: 269e41f4b71Sopenharmony_ci 270e41f4b71Sopenharmony_ci> **NOTE** 271e41f4b71Sopenharmony_ci> 272e41f4b71Sopenharmony_ci> The following data is the accumulated data written in thousands of cycles. To better reflect the difference, the core frequency of the device has been limited. 273e41f4b71Sopenharmony_ci 274e41f4b71Sopenharmony_ci| Container Type | Benchmark Data (us) | 275e41f4b71Sopenharmony_ci| ----------- | ------------------- | 276e41f4b71Sopenharmony_ci| JSArray | 1566.174 | 277e41f4b71Sopenharmony_ci| ArrayBuffer | 3.609 | 278e41f4b71Sopenharmony_ci 279e41f4b71Sopenharmony_ci## Data Conversion 280e41f4b71Sopenharmony_ci 281e41f4b71Sopenharmony_ci**[Suggestion]** Minimize the number of data conversions and avoid unnecessary replication. 282e41f4b71Sopenharmony_ci 283e41f4b71Sopenharmony_ci- Frequent data conversion affects performance. You are advised to use batch data processing or optimize the data structs to improve performance. 284e41f4b71Sopenharmony_ci- During data conversion, use Node-API to access the original data instead of creating a copy. 285e41f4b71Sopenharmony_ci- For the data that may be used in multiple conversions, store it in a buffer to avoid repeated data conversions. In this way, unnecessary calculations can be reduced, leading to better performance. 286e41f4b71Sopenharmony_ci 287e41f4b71Sopenharmony_ci## Module Registration and Naming 288e41f4b71Sopenharmony_ci 289e41f4b71Sopenharmony_ci**[Rule]** 290e41f4b71Sopenharmony_ciAdd "static" to the function corresponding to **nm_register_func** to prevent conflicts with symbols in other .so files. 291e41f4b71Sopenharmony_ci 292e41f4b71Sopenharmony_ciThe module registration entry, that is, the name of the function decorated by **__attribute__((constructor))** must be different from that of other modules. 293e41f4b71Sopenharmony_ci 294e41f4b71Sopenharmony_ciThe **.nm_modname** field must completely match the module name and is case sensitive. 295e41f4b71Sopenharmony_ci 296e41f4b71Sopenharmony_ci**Example (incorrect)** 297e41f4b71Sopenharmony_ciIn the following example, the module name is **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 // static is not added to the function corresponding to nm_register_func. 313e41f4b71Sopenharmony_ci .nm_register_func = Init, 314e41f4b71Sopenharmony_ci // The .nm_modname value does not match the module name. As a result, the module fails to be loaded in the multi-thread scenario. 315e41f4b71Sopenharmony_ci .nm_modname = "entry", 316e41f4b71Sopenharmony_ci .nm_priv = nullptr, 317e41f4b71Sopenharmony_ci .reserved = { 0 }, 318e41f4b71Sopenharmony_ci}; 319e41f4b71Sopenharmony_ci 320e41f4b71Sopenharmony_ci// The name of the module registration entry function is RegisterModule, which is easy to be duplicate with that of other modules. 321e41f4b71Sopenharmony_ciextern "C" __attribute__((constructor)) void RegisterModule() 322e41f4b71Sopenharmony_ci{ 323e41f4b71Sopenharmony_ci napi_module_register(&nativeModule); 324e41f4b71Sopenharmony_ci} 325e41f4b71Sopenharmony_ci``` 326e41f4b71Sopenharmony_ci 327e41f4b71Sopenharmony_ci**Example (correct)** 328e41f4b71Sopenharmony_ciIn the following example, the module name is **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## Using JS Objects Created by napi_create_external APIs 356e41f4b71Sopenharmony_ci 357e41f4b71Sopenharmony_ci**[Rule]** The JS object created by **napi_create_external** APIs can be passed and used only in the calling thread. If it is passed across threads (for example, using **post_message** of the **worker** interface), the application may crash. If a JS object bound with a native object needs to be passed across threads, use **napi_coerce_to_native_binding_object** to bind the two objects. 358e41f4b71Sopenharmony_ci 359e41f4b71Sopenharmony_ci**Example (incorrect)** 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// The code for module registration is omitted here. You may need to register the CreateMyExternal method. 371e41f4b71Sopenharmony_ci``` 372e41f4b71Sopenharmony_ci 373e41f4b71Sopenharmony_ci```ts 374e41f4b71Sopenharmony_ci// index.d.ts 375e41f4b71Sopenharmony_ciexport const createMyExternal: () => Object; 376e41f4b71Sopenharmony_ci 377e41f4b71Sopenharmony_ci// Application code. 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// Close the worker thread. 391e41f4b71Sopenharmony_ci// The application may crash in this step or when the engine performs GC. 392e41f4b71Sopenharmony_cimWorker.terminate(); 393e41f4b71Sopenharmony_ci// The implementation of worker is the default template, which is omitted here. 394e41f4b71Sopenharmony_ci``` 395e41f4b71Sopenharmony_ci 396e41f4b71Sopenharmony_ci## Others 397e41f4b71Sopenharmony_ci 398e41f4b71Sopenharmony_ci**[Rule]** Manual release is not allowed for the third parameter **data** in **napi_get_arraybuffer_info**. Its lifecycle is managed by the engine. 399e41f4b71Sopenharmony_ci 400e41f4b71Sopenharmony_ciThe **napi_get_arraybuffer_info** interface is defined as follows: 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_ciThe parameter **data** specifies the buffer header pointer to ArrayBuffer. This buffer can be read and written in the given range but cannot be released. The buffer memory is managed by the ArrayBuffer Allocator in the engine and is released with the lifecycle of the JS object **ArrayBuffer**. 407e41f4b71Sopenharmony_ci 408e41f4b71Sopenharmony_ci**Example (incorrect)** 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; // This operation is not allowed and may cause a double free of the buffer. The lifecycle of the created arrayBufferPtr is managed by the engine and cannot be manually deleted. 418e41f4b71Sopenharmony_ci``` 419e41f4b71Sopenharmony_ci 420e41f4b71Sopenharmony_ci**[Suggestion]** Properly use **napi_object_freeze** and **napi_object_seal**. 421e41f4b71Sopenharmony_ci 422e41f4b71Sopenharmony_ci**napi_object_freeze** is equivalent to **Object.freeze**. After an object is frozen, all its properties are immutable. **napi_object_seal** is equivalent to **Object.seal**. After an object is sealed, no properties can be added or deleted, but the existing property values are mutable. 423e41f4b71Sopenharmony_ci 424e41f4b71Sopenharmony_ciIf the semantics are violated in strict mode (default), an error will be thrown. 425