开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一)
开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一)
前言——系列介绍
本系列文章主要是记录笔者在鸿蒙南向的学习与工作中的知识点笔记记录,其中不止会针对鸿蒙中的学习问题进行思考与记录,也会对涉及到的一些嵌入式等其他领域知识,自我学习的心得进行记录。
本篇内容主要是黄同学最近在OpenHarmony 南向开发学习中对NAPI框架以及一些代码中的接口,异步实现等机制的学习。
MindMap
NAPI框架简介
Node.js 的 N-API
NAPI
其实是最早应该是来自node.js
中的一个拓展库(也可以说是一整套API接口),叫Node-API
,叫做N-API
。是用来构建本地插件的API,将所有的nodejs底层数据结构黑盒化,封装成二进制接口,这样就可以实现不同版本的Node.js使用同样的接口,其目的是为了简化开发和维护。
NAPI (OpenHarmony)
- NAPI,全称
Native API
,是OpenHarmony系统中的一套原生模块拓展开发框架,基于Nodejs中的N-API开发,为开发者提供了JS与C/C++不同语言模块之间的相互访问,交互的能力。它可以用于规范化封装IO、OS底层等,并可以提供相应的JS接口供开发者调用。当然。N-API
也可以做到这一点。 - 区别于
N-API
,主要在于NAPI针对OpenHarmony 系统做了 一些适配化和优化。但二者的目的都是为了简化和统一原生模块的开发和维护,提高跨平台和跨版本的兼容性。
JS和C/C++互相访问实现原理(浅谈)
鄙人浅谈一下这个东西,欢迎各位斧正!
- 不同的语言的数据类型采用的是
napi_value
类型做封装和转换(计算机网络协议既视感),而像函数等接口则采用如napi_create_function()
以及napi_call_function()
等来进行创建和调用。 - 使用到了 V8 引擎,且对 V8的接口做了 黑盒化 和 抽象化,使得更加稳定。
Code Question
主要是记录一下在读以及编写Code时的遇到的问题的以及自己积累的心得体会。
大多是一些代码中的接口的解释和个人结合相关资料后的一点理解。
#ifdef __cplusplus extern “C”
- 这是一个在cpp中的宏命令,其表示的是如果在cpp文件中,我们需要调用一个C文件的接口
- 背景:
- C 和 C++ 对于函数名字处理的机制不同,众所周知,C++支持函数重载,因此在执行函数时会对名字有特殊处理,但是C不同,C认为函数名只是一个名字。
- 如果需要使用到C中写好的接口,需要使用C方式的链接,因此在需要
extern "C"
来提示编译器在将cpp文件转为汇编时将该处对接口的调用方式由Cpp方式改为C方式,从而可以正确链接。
- 好处:就是方便了开发,使得Cpp对C的兼容性更强,对于已经写得很好的C接口,无需用Cpp再写一份。
_attribute_((constructor))
- 这是GCC一个特有的语法,用来修饰一个函数,从而让该函数在“main”之前执行,所以可以用来做初始化以及其他准备工作,比如初始化块变量或注册回调函数。可以避免一些依赖问题,提高性能。
- 相反,
__attribute__((destructor))
可以修饰函数,使得这个函数在共享库卸载或者程序退出时执行。 - 这两个都是C++ 11 标准中引入的属性指定符序列中的一种,属性指定符序列是一种标准语法。
- 该语法还可以携带一个优先级参数,用于指定多个构造函数的执行顺序,优先级越低,执行越早。
- 区别
static
- static 变量是在全局变量初始化后,main执行之前的,而
__attribute__((constructor))
是在全局变量初始化之前执行,这样可以避免依赖问题。 - static只能在当前文件中使用,而
__attribute__((constructor))
可以在不同文件或者动态链接库中使用。
- static 变量是在全局变量初始化后,main执行之前的,而
NAPI_CALL
- 是一个接口函数,用来调用JS中的函数,参数包括环境变量,接收对象,函数对象,参数个数,参数数组,返回值
- 使用场景
- 封装IO、CPU密集型、OS底层能力,并将JS接口对外暴露。
- 实现JS与C/C++代码的互相访问。
- 优先封装异步方法。
- 该函数与其他类型的接口函数的区别
- 这是一个宏,可以用来检测NAPI函数的返回值是否正确,其他类型的函数需要手动检测。
- 可以调用JS中任意函数,无论是全局还是对象的,其他接口只能调用特定类型以及特定范围的接口。
- 可以在任何地方需要回调的时候调用,不需要额外的参数以及DS。
- 优势
- 简化NAPI函数的调用和错误处理,提高Code的可读性和可维护性。
- 可以方便调用JS中的接口,实现C/C++和JS代码的互相访问
- 任意调用,无需额外的参数以及DS
- 局限性
- 宏,不能作为函数指针传递给其他函数
- 不能直接处理异步操作,需要结合其他接口
- 存在兼容性和稳定性问题。
DELCARE_NAPI_FUCTION
-
这是NAPI的一个宏,看名字大家都知道这个是用来声明一个函数的,黄同学在很多使用NAPI的Cpp代码都能看到这个宏。
-
宏定义原型(参数),有两种形式
// 不传回调 #define DECLARE_NAPI_FUNCTION(modname,name) // 传递回调 #define DECLARE_NAPI_FUNCTION_EX(modname, name, func)
-
两种形式
- 传递三个参数(模块名,函数名,回调函数),这种形式最常见,由开发者定义回调函数的逻辑和返回值。
- 传递两个参数(模块名,函数名),这种形式其实是一种简化写法,会自动使用一个默认的回调函数,将JS传递的参数转换为C的数据类型,并将C函数的返回值转化为napi_value类型返回给JS。
- 在使用宏的时候,会根据传递参数的个数来执行,这种方式其实就是宏的条件编译,而不是 函数重载。
-
实现原理
- 生成一个napi_value类型的函数,调用到napi_create_function函数,创建一个JS对象,并将回调函数作为JS对象的内部数据。
- 将生成的函数添加到一个全局数组中,用于存储所有的NAPI模块接口函数。
- 框架初始化的时候,遍历这个数组,将每个接口导出到JS中,方便调用。
- JS调用接口时,NAPI框架会调出对应的回调函数,并将JS的参数和返回值转化为napi_value,实现JS和C/C++间的交互。
实现原理的流程图,不包括框架初始化
napi_get_cb_info
-
napi的一个函数,用于获取回调函数的参数和其他信息下面是它的原形
napi_status napi_get_cb_info(napi_env env, napi_callback_info cbinfo,size_t* argc, napi_value* argv,napi_value* this_arg, void** data);
参数解释:
- env:环境变量
- cbinfo:回调函数信息
- argc:接收参数个数的指针
- argv:存放参数值的数组
- this_arg 是 JS中的this对象,data是接收数据指针的指针。
NAPI 函数定义限制
这是一条使用框架编写一些C/C++代码作为JS的接口的时需要注意的事情。
黄同学在做一个板子的sample的时候发现,某个smaple的样例源码无法跑通,除了一些简单的语法错误,最主要的是函数定义时的参数类型。
在本身数据是没有NAPI类型的数据的,但是框架中很多接口的定义都是用napi类型,所以我们在定义的时候,传递参数可以用void*
,即空类型传递,然后在函数体内再对应修改即可。否则调用时会不符合NAPI中接口的定义。
异步实现机制
以下内容只讨论计算机方面,不要和我听异步电机啥的,黄同学表示考完控制后,看到电机这个东西真的头很大。
什么是异步
- 异步操作不需要等待结果返回,而同步操作则需要等待。
- 优缺点取决于应用场景
- 异步会提高效率和响应速度,但会增加复杂度和难度。
- 同步比较简单直接,缺点是会造成阻塞和资源浪费。
- 异步和多线程:
- 首先,这是两个东西,虽然黄同学在很多时候也会把这两个东西弄混,但是确实是有区别。
- 区别在于,多线程编程是异步机制的常见实现方式之一,但并不是唯一,所以我们在看很多异步的操作认为是多线程其实是没什么问题的。
在NAPI
中,有两种实现异步操作:**Calllback
**和 Promise
。
Callback
- 就是一般的回调函数机制,相对来说比Promise这种代码逻辑比较复杂,类似常见算法中递归的过程,相对来说,代码的可读性比较差,你只需回想一下你第一次看递归代码的时候大概就知道这种过程了。
- 优点
- 是JS的原生特性,无需额外的库或抽象层。
- 可以在完成异步操作后执行一些操作。
- 缺点
- 代码的可读性和可维护性差,当多个回调嵌套时,就会出现传说中的 回调地狱。
- 对错误处理变得复杂,因为每个回调都需要检查错误并传递给下一个回调。
- 不能返回多个参数,只能返回一个对象(有些资料对这个的解释是Callback是以参数的形式返回结果,但是并不准确,参考JS官方文档以及javascript - How do you properly return multiple values from a Promise? - Stack Overflow等内容,所谓的参数应该是一个参数,或者说是参数就是对象)
- Code(JS)
// 定义一个异步的除法函数,接受两个数字和两个回调函数作为参数
function divisionAPI(number, divider, successCallback, errorCallback)
{if (divider == 0) {return errorCallback(new Error("Division by zero"));}successCallback(number / divider);
}// 调用异步的除法函数,传入两个数字和两个回调函数
divisionAPI(10, 2, function(result) {// 成功的回调函数,打印结果console.log("The result is " + result);
}, function(error) {// 失败的回调函数,打印错误console.error("Something went wrong: " + error.message);
});
Promise
- Promise 其实就是一种封装的异步操作结果的对象。
- 三种状态
pending
,等待fulfilled
,已成功rejected
,已失败
- 优点:
- 可以采用同步的方式编写异步代码,因为异步操作结果已经被封装成了Promise,这样可以避免回调地狱。
- Promise对象本身是用链式而不是回调的方式调用,利用链式调用可以组合多个异步操作,并且可以用
then
或者catch
操作来处理异步操作结果成功或者失败的情况。 - 比较灵活,可以用
all
方法等待所有异步操作的完成,也可以用race
方法来获取最先完成的异步操作的结果。
- 缺点
- 因为做了一定程度的封装,用对象来存储异步操作的结果,其实就会消耗一些额外的内存和性能。
- 违背异步非阻塞I/O的原则,因为需要等待异步操作的完成(当从pending变到fulfilled或者rejected时,这个过程是不可逆的,使用
await
关键字在async函数中,等待一个Promise对象,实际过程就是再那个时间段代码调用到异步操作,此时async不执行,有点类似于同步操作,或者说我们一开始学习编程时最简单的函数调用,详见asynchronous - Why use promise or async/await on child processes in Node.js? - Stack Overflow 和 How to use promises - Learn web development | MDN (mozilla.org))。 - 也是只能返回一个对象。
- Code(JS)
// 定义一个异步的除法函数,返回一个Promise对象
function divisionAPI(number, divider) {return new Promise(function(resolve, reject) {if (divider == 0) {return reject(new Error("Division by zero"));}resolve(number / divider);});
}// 调用异步的除法函数,返回一个Promise对象
divisionAPI(10, 2).then(function(result) {// 成功的回调函数,打印结果console.log("The result is " + result);}).catch(function(error) {// 失败的回调函数,打印错误console.error("Something went wrong: " + error.message);});
参考资料
黄同学写这篇blog的一些参考资料,有需要的可以看看。
- OpenHarmony 源码解析之NAPI框架内部实现分析-51CTO.COM
- [三方库移植之NAPI开发1]—Hello OpenHarmony NAPI - 知乎 (zhihu.com)
- ace_napi: Development framework for extending the JS Native Module | 原生模块扩展开发框架 (gitee.com)
- vendor_unionman: 该仓库托管广东九联科技股份有限公司厂商驱动及配置文件 - Gitee.com
- 写一个N-API没那么难? - 知乎 (zhihu.com)
- 为JS写C++扩展,Napi第一步_napi.h_番茄V王子的博客-CSDN博客
- c++ - How to save an asynchronous callback for later using node-addon-api / napi - Stack Overflow
- 三方库移植之NAPI开发–异步调用:Callback&Promise(四)-51CTO.COM
- 箭头函数表达式 - JavaScript |多核 (mozilla.org)
- What are the pros and cons of using promises instead of callbacks? - Best Interview Question
- asynchronous - Why use promise or async/await on child processes in Node.js? - Stack Overflow
- How to use promises - Learn web development | MDN (mozilla.org)
相关文章:
开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一)
开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一) 前言——系列介绍 本系列文章主要是记录笔者在鸿蒙南向的学习与工作中的知识点笔记记录,其中不止会针对鸿蒙中的学习问题进行思考与记录,也会对涉及到的一些嵌入式等其他领域知识&…...
Spring - Spring框架概述面试题总结
文章目录01. 什么是Spring?02. Spring框架的设计目标,设计理念,和核心是什么?03. Spring的优点是什么?04. Spring框架中都用到了哪些设计模式?05. Spring有哪些应用场景?06. Spring由哪些模块组成…...
学习python好就业么
Python的普及与数据挖掘、人工智能和数值计算等领域的蓬勃发展相关,但同时也与普遍编程需求的增加有关。 Python作为人工智能的头号语言,一方面会吸引大量计划从事人工智能的人来学习,另一方面自然也带动了网络上对这门“新语言”的关注和讨…...
瑞幸咖啡的最终目标并不是做国内市场大哥
出品 | 何玺 排版 | 叶媛 日前,瑞幸咖啡发布2022年第四季度及全年财报。数据显示,在刚刚过去的2022年,瑞幸咖啡首次实现了营收超百亿,门店规模也超越老对手星巴克,成为了国内第一连锁咖啡品牌。 那么,瑞幸…...
GPT 模型介绍 | GPT3 / GPT3.5 + Flask | Github源码链接
1. 模型介绍 Chatgpt 使用与 InstructGPT相同的方法,使用来自人类反馈的强化学习 (RLHF) 来训练该模型,但数据收集设置略有不同。我们使用监督微调训练了一个初始模型:人类 AI 训练员提供对话,他们在对话中扮演双方——用户和 AI…...
蓝桥杯入门即劝退(二十六)组合问题(回溯算法)
-----持续更新Spring入门系列文章----- 如果你也喜欢Java和算法,欢迎订阅专栏共同学习交流! 你的点赞、关注、评论、是我创作的动力! -------希望我的文章对你有所帮助-------- 专栏:蓝桥杯系列 一、题目描述 给定两个整数 n …...
现代卷积神经网络(ResNet)
专栏:神经网络复现目录 本章介绍的是现代神经网络的结构和复现,包括深度卷积神经网络(AlexNet),VGG,NiN,GoogleNet,残差网络(ResNet),稠密连接网络…...
PTA:L1-019 谁先倒、L1-020 帅到没朋友、L1-021 重要的话说三遍(C++)
目录 L1-019 谁先倒 问题描述: L1-020 帅到没朋友 问题描述: 实现代码(只过了部分): L1-021 重要的话说三遍 问题描述: 实现代码: 无解析 L1-019 谁先倒 问题描述: 划拳是…...
STL常见容器之set/multiset、map/multimap
set/multiset—集合容器 特点 所有元素都会在插入时自动被排序 本质 set/multiset属于关联式容器,底层结构是二叉树实现 set和multiset区别 set不可以插入重复数据,而multiset可以set插入数据的同时会返回插入结果,表示插入是否成功multiset…...
ThreadLocal 实现原理
每个 Thread 中都存储着一个成员变量:ThreadLocalMap /** InheritableThreadLocal values pertaining to this thread. This map is* maintained by the InheritableThreadLocal class.*/ThreadLocal.ThreadLocalMap inheritableThreadLocals null; ThreadLocal 本…...
BUUCTF [羊城杯 2020]easyre 题解
一.查壳 64位无壳 二.主函数逻辑 可以得知flag长度为38,然后进行三次加密 第一次加密是base64加密,得到code1 第二次加密是将code1拆成四段赋给code2 第三次加密是将code2内的数字和字母移3位,其他字符不变 str2保存的是最终的加密字符 三.encode_one_base64 看到主函数…...
网络协议(十二):HTTPS(SSL/TLS、TLS1.2的连接)
网络协议系列文章 网络协议(一):基本概念、计算机之间的连接方式 网络协议(二):MAC地址、IP地址、子网掩码、子网和超网 网络协议(三):路由器原理及数据包传输过程 网络协议(四):网络分类、ISP、上网方式、公网私网、NAT 网络…...
九九乘法表--课后程序(Python程序开发案例教程-黑马程序员编著-第3章-课后作业)
实例9:九九乘法表 乘法口诀是中国古代筹算中进行乘法、除法、开方等运算的基本计算规则,沿用至今已有两千多年。古代的乘法口诀与现在使用的乘法口诀顺序相反,自上而下从“九九八十一”开始到“一一如一”为止,因此,古…...
在超算上安装文件树命令tree
超算平台使用的centos系统没有内置tree命令,需要通过源码安装。记录安装流程如下。 1. 下载源码包 下载链接如下: http://mama.indstate.edu/users/ice/tree/ 选择“Download the latest version” 如本文下载了源码包“tree-2.1.0.tgz”. 2. 源码包…...
论文投稿指南——中文核心期刊推荐(经济管理)
【前言】 🚀 想发论文怎么办?手把手教你论文如何投稿!那么,首先要搞懂投稿目标——论文期刊 🎄 在期刊论文的分布中,存在一种普遍现象:即对于某一特定的学科或专业来说,少数期刊所含…...
在vue中如果computed属性是一个异步操作怎么办?
在计算属性中使用异步方法时,可以使用async/await来处理异步操作。由于计算属性是基于它们的依赖缓存的,所以我们需要使用一个返回Promise的异步方法来确保计算属性能够正常运行。 下面是一个简单的示例,演示如何在计算属性中使用异步方法&am…...
SRP合批问题
1)SRP合批问题 2)多个Base相机渲染到同一个渲染目标,移动平台花屏的问题 3)粒子系统对GPU Instancing的支持 4)如何修改URP下场景和UI分辨率分离(不需要改颜色空间) 这是第327篇UWA技术知识分…...
蓝牙5.1低功耗SOC 私有协议2.4GHz芯片HS6621
HS6621CxC是一个优化功耗真正芯片系统(SOC)解决方案,适用于蓝牙低功耗和私有的2.4GHz应用场景。它集成了一个高性能、小功率的射频收发器,具有蓝牙基带和丰富的外围IO扩展。还集成了电源管理,以提供高效的电源管理。 …...
数据库连接池
数据库连接---执行完毕---释放 连接--释放 十分浪费系统资源 池化技术:准备一些预先的资源,过来就连接预先准备好的 最小连接数: 10 最大连接数:15 业务最高承载上限 排队等待, 等待超时:100…...
Arrays-sort-的用法
1.集合交换元素 Collections.swap(List<?> list, int i, int j); 源码: /*** Swaps the elements at the specified positions in the specified list.* (If the specified positions are equal, invoking this method …...
华为OD机试真题Java实现【寻找相同子串】真题+解题思路+代码(20222023)
寻找相同子串 题目 给你两个字符串 t 和 p ,要求从 t 中找到一个和 p 相同的连续子串,并输出该字串第一个字符的下标。 🔥🔥🔥🔥🔥👉👉👉👉👉👉 华为OD机试(Java)真题目录汇总 输入描述: 输入文件包括两行,分别表示字符串 t 和 p ,保证 t 的长度…...
性能指标 确定性能目标 性能场景设计
性能测试指标 性能测试指标分为业务技术指标和系统资源指标,在服务端性能业务技术指标中分为三个指标,系统吞吐量,响应时间和并发用户数。响应时间分为前端展现时间和系统响应时间两部分,系统吞吐量体现软件系统负载承受能力的指…...
ENVI_Classic:快速入门_菜单栏常见功能的基本介绍
说明:由于实验要求,所以并没有对各个功能进行详尽的解释,大多点到为止,少部分实验内容是实验要求所以步骤详尽。当然由于经验不足,有一些可能存在错误恳请指正.1. 实验目的通过ENVI Classic对自行下载的遥感图像进行一…...
【深度探讨】公共部门在选择区块链平台时要考虑的6个方面
发表时间:2022年8月17日 信息来源:bsvblockchain.org 与私营企业相比,全球的公共部门组织在考虑升级软件解决方案时面临着一系列的全新挑战。公共部门的决策流程冗长而复杂,他们要不惜一切代价避免对现有业务造成干扰,…...
基于阿里云物联网平台设计的实时图传系统_采用MQTT协议传输图像
一、项目功能介绍 当前基于MQTT协议设计了一个实时图传系统,通过这个项目来演示,两个MQTT设备如何互相订阅,进行消息流转。 在阿里云服务器上创建2个设备,分为为设备A和设备B;设备A负责采集本地摄像头画面上传,设备B负责接收设备A上传的数据然后解析显示出来。在阿里云服…...
42-Golang中的单元测试
Golang中的单元测试需求传统方法基本介绍单元测试快速入门总结综合案例需求 在工作中,我们会遇到这样的情况,就是去确认一个函数,或者一个模块的结果是否正确 传统方法 在main函数中,调用addUpper函数,看看实际输出…...
python实现k_means聚类
K-Means算法是将一组N个样本的特征矩阵X划分为K个无交集的簇,直观上来看是簇是一组一组聚集在一起的数据,在一个簇中的数据就认为是同一类。簇就是聚类的结果表现。簇中所有数据的均值通常被称为这个簇的“质心”(Centroids)。在一个二维平面中ÿ…...
【批处理脚本】-3.3-exit命令详解
"><--点击返回「批处理BAT从入门到精通」总目录--> 共3页精讲(列举了所有exit的用法,图文并茂,通俗易懂) 在从事“嵌入式软件开发”和“Autosar工具开发软件”过程中,经常会在其集成开发环境IDE(CodeWarrior,S32K DS,Davinci,EB Tresos,ETAS…)中,…...
如果读了我2011年求职前端开发的酸爽经历,希望你可以鼓起勇气继续向前
今年是2023年,如果你觉得今年找工作很难,狗哥回忆了一下2011年求职前端开发工作的酸爽经历,希望你读了以后可以鼓起勇气,不要迷茫,简历投出去石沉大海的,需要改简历的就赶紧改,刷题不到位的就赶…...
PTA:L1-016 查验身份证、L1-017 到底有多二、L1-018 大笨钟(C++)
目录 PTA:L1-016 查验身份证 问题描述: 实现代码: L1-017 到底有多二 问题描述: 实现代码: L1-018 大笨钟 问题描述: 实现代码: 都是简单模拟题,不再写题解。 PTA…...
公司网站推广的方法/2022最新引流推广平台
作者:洪斌 问题背景 在5.6.29和5.7.11版本之前,当binlog格式设置成mixed时,创建event事件中包含sysdate函数时,会导致复制中断。 【与此bug相关】 场景重现 测试版本:mysql 5.6.23重现方法:分别设置sta…...
接做网站的私活怎么报价/搜搜
点击上方“蓝色字”可关注我们!暴走时评:中国国有商业银行之一交通银行目前已经通过其专有的区块链网络"聚财链"完成了大量住宅抵押贷款支持的证券(RMBSs)发行,价值93亿元(约合13亿美元ÿ…...
日本传统颜色 网站/渠道推广策略
idpid问题描述:102031415262738495取出id为1及其下属的所有的数据,结果为下idpid1031417384SQL> CREATE TABLE TBL_TEST2 (3 ID NUMBER,4 NAME VARCHAR2(100 BYTE),5 PID NUMBER DEFAULT 06 );Table createdS…...
做网站多少钱google/网站制作的费用
前话 大家好 ,这是我的第一篇博客 ,我今年是一名大二的学生 ,今年21岁, 最近听到许多程序员有写博客的想法 ,所以我就有了突发奇想,准备开始写博客。记得我大一开学的时候 我申请了一个公众号:计…...
wordpress插件样式/种子搜索引擎
10月26日,锐捷网络在京发布最新网络威胁治理解决方案,并正式推出大数据安全平台RG-BDS。作为中国数据通信解决方案领导品牌,锐捷网络近年来在深入扎根行业的基础上,陆续推出了大量贴近用户应用场景的解决方案,以及可支…...
游戏的网站策划应该怎么做/夸克搜索网页版
SQL 教程 | 菜鸟教程 http://www.runoob.com/sql/sql-tutorial.html SQL,指结构化查询语言,全称是 Structured Query Language。SELECT TOP 子句用于规定要返回的记录的数目。SELECT TOP 子句对于拥有数千条记录的大型表来说,是非常有用的。注…...