建设网站需要几级安全等保,网站开发售后服务承诺,免费开店的平台,网站框架设计理念当传入napi_get_cb_info的argv不为nullptr时#xff0c;argv的长度必须大于等于传入argc声明的大小。
当argv不为nullptr时#xff0c;napi_get_cb_info会根据argc声明的数量将JS实际传入的参数写入argv。如果argc小于等于实际JS传入参数的数量#xff0c;该接口仅会将声明…当传入napi_get_cb_info的argv不为nullptr时argv的长度必须大于等于传入argc声明的大小。
当argv不为nullptr时napi_get_cb_info会根据argc声明的数量将JS实际传入的参数写入argv。如果argc小于等于实际JS传入参数的数量该接口仅会将声明的argc数量的参数写入argv而当argc大于实际参数数量时该接口会在argv的尾部填充undefined。
错误示例
static napi_value IncorrectDemo1(napi_env env, napi_callbackk_info info) {// argc 未正确的初始化其值为不确定的随机值导致 argv 的长度可能小于 argc 声明的数量数据越界。size_t argc;napi_value argv[10] {nullptr};napi_get_cb_info(env, info, argc, argv, nullptr, nullptr);return nullptr;
}static napi_value IncorrectDemo2(napi_env env, napi_callback_info info) {// argc 声明的数量大与 argv 实际初始化的长度导致 napi_get_cb_info 接口在写入 argv 时数据越界。size_t argc 5;napi_value argv[3] {nullptr};napi_get_cb_info(env, info, argc, argv, nullptr, nullptr);return nullptr;
}正确示例
static napi_value GetArgvDemo1(napi_env env, napi_callback_info info) {size_t argc 0;// argv 传入 nullptr 来获取传入参数真实数量napi_get_cb_info(env, info, argc, nullptr, nullptr, nullptr);// JS 传入参数为0不执行后续逻辑if (argc 0) {return nullptr;}// 创建数组用以获取JS传入的参数napi_value* argv new napi_value[argc]; napi_get_cb_info(env, info, argc, argv, nullptr, nullptr);// 业务代码// ... ...// argv 为 new 创建的对象在使用完成后手动释放delete argv;return nullptr;
}static napi_value GetArgvDemo2(napi_env env, napi_callback_info info) {size_t argc 2;napi_value* argv[2] {nullptr}; // napi_get_cb_info 会向 argv 中写入 argc 个 JS 传入参数或 undefinednapi_get_cb_info(env, info, argc, nullptr, nullptr, nullptr);// 业务代码// ... ...return nullptr;
}生命周期管理
【规则】 合理使用napi_open_handle_scope和napi_close_handle_scope管理napi_value的生命周期做到生命周期最小化避免发生内存泄漏问题。
每个napi_value属于特定的HandleScopeHandleScope通过napi_open_handle_scope和napi_close_handle_scope来建立和关闭HandleScope关闭后所属的napi_value就会自动释放。
正确示例
// 在for循环中频繁调用napi接口创建js对象时要加handle_scope及时释放不再使用的资源。
// 下面例子中每次循环结束局部变量res的生命周期已结束因此加scope及时释放其持有的js对象防止内存泄漏
for (int i 0; i 100000; i) { napi_handle_scope scope nullptr; napi_open_handle_scope(env, scope); if (scope nullptr) { return; } napi_value res; napi_create_object(env, res); napi_close_handle_scope(env, scope);
}上下文敏感
【规则】 多引擎实例场景下禁止通过Node-API跨引擎实例访问JS对象。
引擎实例是一个独立运行环境JS对象创建访问等操作必须在同一个引擎实例中进行。若在不同引擎实例中操作同一个对象可能会引发程序崩溃。引擎实例在接口中体现为napi_env。
错误示例
// 线程1执行在env1创建string对象值为bar、
napi_create_string_utf8(env1, bar, NAPI_AUTO_LENGTH, string);
// 线程2执行在env2创建object对象并将上述的string对象设置到object对象中
napi_status status napi_create_object(env2, object);
if (status ! napi_ok) { napi_throw_error(env, ...); return;
} status napi_set_named_property(env2, object, foo, string);
if (status ! napi_ok) { napi_throw_error(env, ...); return;
}所有的JS对象都隶属于具体的某一napi_env不可将env1的对象设置到env2中的对象中。在env2中一旦访问到env1的对象程序可能会发生崩溃。
异常处理
【建议】 Node-API接口调用发生异常需要及时处理不能遗漏异常到后续逻辑否则程序可能发生不可预期行为。
正确示例
// 1.创建对象
napi_status status napi_create_object(env, object);
if (status ! napi_ok) { napi_throw_error(env, ...); return;
}
// 2.创建属性值
status napi_create_string_utf8(env, bar, NAPI_AUTO_LENGTH, string);
if (status ! napi_ok) { napi_throw_error(env, ...); return;
}
// 3.将步骤2的结果设置为对象object属性foo的值
status napi_set_named_property(env, object, foo, string);
if (status ! napi_ok) { napi_throw_error(env, ...); return;
}如上示例中步骤1或者步骤2出现异常时步骤3都不会正常进行。只有当方法的返回值是napi_ok时才能保持继续正常运行否则后续流程可能会出现不可预期的行为。
异步任务
【规则】 当使用uv_queue_work方法将任务抛到JS线程上面执行的时候对JS线程的回调方法一般情况下需要加上napi_handle_scope来管理回调方法创建的napi_value的生命周期。
使用uv_queue_work方法不会走Node-API框架此时需要开发者自己合理使用napi_handle_scope来管理napi_value的生命周期。
正确示例
void callbackTest(CallbackContext* context)
{ uv_loop_s* loop nullptr; napi_get_uv_event_loop(context-env, loop); uv_work_t* work new uv_work_t; context-retData 1; work-data (void*)context; uv_queue_work( loop, work, [](uv_work_t* work) {}, // using callback function back to JS thread [](uv_work_t* work, int status) { CallbackContext* context (CallbackContext*)work-data; napi_handle_scope scope nullptr; napi_open_handle_scope(context-env, scope); if (scope nullptr) { return; } napi_value callback nullptr; napi_get_reference_value(context-env, context-callbackRef, callback); napi_value retArg; napi_create_int32(context-env, context-retData, retArg); napi_value ret; napi_call_function(context-env, nullptr, callback, 1, retArg, ret); napi_delete_reference(context-env, context-callbackRef); napi_close_handle_scope(context-env, scope); if (work ! nullptr) { delete work; } delete context; } );
}对象绑定
【规则】 使用napi_wrap接口如果最后一个参数result传递不为nullptr需要开发者在合适的时机调用napi_remove_wrap函数主动删除创建的napi_ref。
napi_wrap接口定义如下
napi_wrap(napi_env env, napi_value js_object, void* native_object, napi_finalize finalize_cb, void* finalize_hint, napi_ref* result)当最后一个参数result不为空时框架会创建一个napi_ref对象指向js_object。此时开发者需要自己管理js_object的生命周期即需要在合适的时机调用napi_remove_wrap删除napi_ref这样GC才能正常释放js_object从而触发绑定C对象native_object的析构函数finalize_cb。
一般情况下根据业务情况最后一个参数result可以直接传递为nullptr。
正确示例
// 用法1napi_wrap不需要接收创建的napi_ref最后一个参数传递nullptr创建的napi_ref是弱引用由系统管理不需要用户手动释放
napi_wrap(env, jsobject, nativeObject, cb, nullptr, nullptr) // 用法2napi_wrap需要接收创建的napi_ref最后一个参数不为nullptr返回的napi_ref是强引用需要用户手动释放否则会内存泄漏
napi_ref result;
napi_wrap(env, jsobject, nativeObject, cb, nullptr, result)
// 当js_object和result后续不再使用时及时调用napi_remove_wrap释放result
napi_value result1;
napi_remove_wrap(env, jsobject, result1);高性能数组
【建议】 存储值类型数据时使用ArrayBuffer代替JSArray来提高应用性能。
使用JSArray作为容器储存数据支持几乎所有的JS数据类型。
使用napi_set_element方法对JSArray存储值类型数据如int32时同样会涉及到与运行时的交互造成不必要的开销。
ArrayBuffer进行增改是直接对缓冲区进行更改具有远优于使用napi_set_element操作JSArray的性能表现。
因此此种场景下更推荐使用napi_create_arraybuffer接口创建的ArrayBuffer对象。
示例
// 以下代码使用常规JSArray作为容器但其仅存储int32类型数据。
// 但因为是JS对象因此只能使用napi方法对其进行增改性能较低。
static napi_value ArrayDemo(napi_env env, napi_callback_info info)
{constexpr size_t arrSize 1000;napi_value jsArr nullptr;napi_create_array(env, jsArr);for (int i 0; i arrSize; i) {napi_value arrValue nullptr;napi_create_int32(env, i, arrValue);// 常规JSArray使用napi方法对array进行读写性能较差。napi_set_element(env, jsArr, i, arrValue);}return jsArr;
}// 推荐写法
// 同样以int32类型数据为例但以下代码使用ArrayBuffer作为容器。
// 因此可以使用C/C的方法直接对缓冲区进行增改。
static napi_value ArrayBufferDemo(napi_env env, napi_callback_info info)
{constexpr size_t arrSize 1000;napi_value arrBuffer nullptr;void* data nullptr;napi_create_arraybuffer(env, arrSize * sizeof(int32_t), data, arrBuffer);int32_t* i32Buffer reinterpret_castint32_t*(data);for (int i 0; i arrSize; i) {// arrayBuffer直接对缓冲区进行修改跳过运行时// 与操作原生C/C对象性能相当i32Buffer[i] i;}return arrBuffer;
}napi_create_arraybuffer等同于JS代码中的new ArrayBuffer(size)其生成的对象不可直接在TS/JS中进行读取需要将其包装为TyppedArray或DataView后方可进行读写。
基准性能测试结果如下 说明 以下数据为千次循环写入累计数据为更好的体现出差异已对设备核心频率进行限制。 容器类型Benchmark数据usJSArray1566.174ArrayBuffer3.609
数据转换
【建议】 尽可能的减少数据转换次数避免不必要的复制。
减少数据转换次数 频繁的数据转换可能会导致性能下降可以通过批量处理数据或者使用更高效的数据结构来优化性能避免不必要的数据复制 在进行数据转换时可以使用Node-API提供的接口来直接访问原始数据而不是创建新的副本使用缓存 如果某些数据在多次转换中都会被使用到可以考虑使用缓存来避免重复的数据转换。缓存可以减少不必要的计算提高性能。
其它
【规则】 使用napi_get_arraybuffer_info接口第三个参数data资源开发者不允许释放data的生命周期受引擎管理。
napi_get_arraybuffer_info接口定义如下
napi_get_arraybuffer_info(napi_env env, napi_value arraybuffer, void** data, size_t* byte_length)data获取的是ArrayBuffer的Buffer头指针开发者只可以在范围内读写该Buffer区域不可以进行释放操作。该段内存由引擎内部的ArrayBuffer Allocator管理随JS对象ArrayBuffer的生命周期释放。
错误示例
void* arrayBufferPtr nullptr;
napi_value arrayBuffer nullptr;
size_t createBufferSize ARRAY_BUFFER_SIZE;
napi_status verification napi_create_arraybuffer(env, createBufferSize, arrayBufferPtr, arrayBuffer);
size_t arrayBufferSize;
napi_status result napi_get_arraybuffer_info(env, arrayBuffer, arrayBufferPtr, arrayBufferSize);
delete arrayBufferPtr; // 这一步是禁止的创建的arrayBufferPtr生命周期由引擎管理不允许用户自己delete否则会double free【建议】 合理使用napi_object_freeze和napi_object_seal来控制对象以及对象属性的可变性。
napi_object_freeze等同于Object.freeze语义freeze后对象的所有属性都不可能以任何方式被修改napi_object_seal等同于Object.seal语义对象不可增删属性。两者的主要区别是freeze不能改属性的值seal还可以改属性的值。
开发者使用以上语义时需确保约束条件是自己需要的一旦违背以上语义严格模式下就会抛出Error默认严格模式。
为了能让大家更好的学习鸿蒙HarmonyOS NEXT开发技术这边特意整理了《鸿蒙开发学习手册》共计890页希望对大家有所帮助https://qr21.cn/FV7h05
《鸿蒙开发学习手册》
如何快速入门https://qr21.cn/FV7h05
基本概念构建第一个ArkTS应用…… 开发基础知识https://qr21.cn/FV7h05
应用基础知识配置文件应用数据管理应用安全管理应用隐私保护三方应用调用管控机制资源分类与访问学习ArkTS语言…… 基于ArkTS 开发https://qr21.cn/FV7h05
Ability开发UI开发公共事件与通知窗口管理媒体安全网络与链接电话服务数据管理后台任务(Background Task)管理设备管理设备使用信息统计DFX国际化开发折叠屏系列…… 鸿蒙开发面试真题含参考答案https://qr18.cn/F781PH 鸿蒙开发面试大盘集篇共计319页https://qr18.cn/F781PH
1.项目开发必备面试题 2.性能优化方向 3.架构方向 4.鸿蒙开发系统底层方向 5.鸿蒙音视频开发方向 6.鸿蒙车载开发方向 7.鸿蒙南向开发方向