开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一)

news/2024/4/27 20:55:51/文章来源:https://blog.csdn.net/weixin_54891898/article/details/129386948

开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一)

前言——系列介绍

本系列文章主要是记录笔者在鸿蒙南向的学习与工作中的知识点笔记记录,其中不止会针对鸿蒙中的学习问题进行思考与记录,也会对涉及到的一些嵌入式等其他领域知识,自我学习的心得进行记录。

本篇内容主要是黄同学最近在OpenHarmony 南向开发学习中对NAPI框架以及一些代码中的接口,异步实现等机制的学习。

MindMap

在这里插入图片描述

NAPI框架简介

Node.js 的 N-API

NAPI 其实是最早应该是来自node.js中的一个拓展库(也可以说是一整套API接口),叫Node-API,叫做N-API。是用来构建本地插件的API,将所有的nodejs底层数据结构黑盒化,封装成二进制接口,这样就可以实现不同版本的Node.js使用同样的接口,其目的是为了简化开发和维护。

NAPI (OpenHarmony)

  1. NAPI,全称 Native API,是OpenHarmony系统中的一套原生模块拓展开发框架,基于Nodejs中的N-API开发,为开发者提供了JS与C/C++不同语言模块之间的相互访问,交互的能力。它可以用于规范化封装IO、OS底层等,并可以提供相应的JS接口供开发者调用。当然。N-API也可以做到这一点。
  2. 区别于 N-API主要在于NAPI针对OpenHarmony 系统做了 一些适配化和优化。但二者的目的都是为了简化和统一原生模块的开发和维护,提高跨平台和跨版本的兼容性。

JS和C/C++互相访问实现原理(浅谈)

鄙人浅谈一下这个东西,欢迎各位斧正!

  1. 不同的语言的数据类型采用的是 napi_value类型做封装和转换(计算机网络协议既视感),而像函数等接口则采用如 napi_create_function() 以及 napi_call_function() 等来进行创建和调用。
  2. 使用到了 V8 引擎,且对 V8的接口做了 黑盒化抽象化,使得更加稳定。

Code Question

主要是记录一下在读以及编写Code时的遇到的问题的以及自己积累的心得体会。

大多是一些代码中的接口的解释和个人结合相关资料后的一点理解。

#ifdef __cplusplus extern “C”

  1. 这是一个在cpp中的宏命令,其表示的是如果在cpp文件中,我们需要调用一个C文件的接口
  2. 背景:
    1. C 和 C++ 对于函数名字处理的机制不同,众所周知,C++支持函数重载,因此在执行函数时会对名字有特殊处理,但是C不同,C认为函数名只是一个名字。
    2. 如果需要使用到C中写好的接口,需要使用C方式的链接,因此在需要 extern "C" 来提示编译器在将cpp文件转为汇编时将该处对接口的调用方式由Cpp方式改为C方式,从而可以正确链接。
  3. 好处:就是方便了开发,使得Cpp对C的兼容性更强,对于已经写得很好的C接口,无需用Cpp再写一份。

_attribute_((constructor))

  1. 这是GCC一个特有的语法,用来修饰一个函数,从而让该函数在“main”之前执行,所以可以用来做初始化以及其他准备工作,比如初始化块变量或注册回调函数。可以避免一些依赖问题,提高性能。
  2. 相反,__attribute__((destructor))可以修饰函数,使得这个函数在共享库卸载或者程序退出时执行。
  3. 这两个都是C++ 11 标准中引入的属性指定符序列中的一种,属性指定符序列是一种标准语法。
  4. 该语法还可以携带一个优先级参数,用于指定多个构造函数的执行顺序,优先级越低,执行越早。
  5. 区别static
    1. static 变量是在全局变量初始化后,main执行之前的,而__attribute__((constructor))是在全局变量初始化之前执行,这样可以避免依赖问题。
    2. static只能在当前文件中使用,而__attribute__((constructor))可以在不同文件或者动态链接库中使用。

NAPI_CALL

  1. 是一个接口函数,用来调用JS中的函数,参数包括环境变量,接收对象,函数对象,参数个数,参数数组,返回值
  2. 使用场景
    1. 封装IO、CPU密集型、OS底层能力,并将JS接口对外暴露。
    2. 实现JS与C/C++代码的互相访问。
    3. 优先封装异步方法。
  3. 该函数与其他类型的接口函数的区别
    1. 这是一个宏,可以用来检测NAPI函数的返回值是否正确,其他类型的函数需要手动检测。
    2. 可以调用JS中任意函数,无论是全局还是对象的,其他接口只能调用特定类型以及特定范围的接口。
    3. 可以在任何地方需要回调的时候调用,不需要额外的参数以及DS。
  4. 优势
    1. 简化NAPI函数的调用和错误处理,提高Code的可读性和可维护性。
    2. 可以方便调用JS中的接口,实现C/C++和JS代码的互相访问
    3. 任意调用,无需额外的参数以及DS
  5. 局限性
    1. 宏,不能作为函数指针传递给其他函数
    2. 不能直接处理异步操作,需要结合其他接口
    3. 存在兼容性和稳定性问题。

DELCARE_NAPI_FUCTION

  1. 这是NAPI的一个宏,看名字大家都知道这个是用来声明一个函数的,黄同学在很多使用NAPI的Cpp代码都能看到这个宏。

  2. 宏定义原型(参数),有两种形式

    // 不传回调
    #define DECLARE_NAPI_FUNCTION(modname,name)
    // 传递回调
    #define DECLARE_NAPI_FUNCTION_EX(modname, name, func) 
    
  3. 两种形式

    1. 传递三个参数(模块名,函数名,回调函数),这种形式最常见,由开发者定义回调函数的逻辑和返回值。
    2. 传递两个参数(模块名,函数名),这种形式其实是一种简化写法,会自动使用一个默认的回调函数,将JS传递的参数转换为C的数据类型,并将C函数的返回值转化为napi_value类型返回给JS。
    3. 在使用宏的时候,会根据传递参数的个数来执行,这种方式其实就是宏的条件编译,而不是 函数重载
  4. 实现原理

    1. 生成一个napi_value类型的函数,调用到napi_create_function函数,创建一个JS对象,并将回调函数作为JS对象的内部数据。
    2. 将生成的函数添加到一个全局数组中,用于存储所有的NAPI模块接口函数。
    3. 框架初始化的时候,遍历这个数组,将每个接口导出到JS中,方便调用。
    4. JS调用接口时,NAPI框架会调出对应的回调函数,并将JS的参数和返回值转化为napi_value,实现JS和C/C++间的交互。

实现原理的流程图,不包括框架初始化

在这里插入图片描述

napi_get_cb_info

  1. 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);
    

    参数解释:

    1. env:环境变量
    2. cbinfo:回调函数信息
    3. argc:接收参数个数的指针
    4. argv:存放参数值的数组
    5. this_arg 是 JS中的this对象,data是接收数据指针的指针。

NAPI 函数定义限制

这是一条使用框架编写一些C/C++代码作为JS的接口的时需要注意的事情。

黄同学在做一个板子的sample的时候发现,某个smaple的样例源码无法跑通,除了一些简单的语法错误,最主要的是函数定义时的参数类型。

在本身数据是没有NAPI类型的数据的,但是框架中很多接口的定义都是用napi类型,所以我们在定义的时候,传递参数可以用void*,即空类型传递,然后在函数体内再对应修改即可。否则调用时会不符合NAPI中接口的定义。

异步实现机制

以下内容只讨论计算机方面,不要和我听异步电机啥的,黄同学表示考完控制后,看到电机这个东西真的头很大。

什么是异步

  1. 异步操作不需要等待结果返回,而同步操作则需要等待。
  2. 优缺点取决于应用场景
    1. 异步会提高效率和响应速度,但会增加复杂度和难度。
    2. 同步比较简单直接,缺点是会造成阻塞和资源浪费。
  3. 异步和多线程:
    1. 首先,这是两个东西,虽然黄同学在很多时候也会把这两个东西弄混,但是确实是有区别。
    2. 区别在于,多线程编程是异步机制的常见实现方式之一,但并不是唯一,所以我们在看很多异步的操作认为是多线程其实是没什么问题的。

NAPI中,有两种实现异步操作:**Calllback **和 Promise

Callback

  1. 就是一般的回调函数机制,相对来说比Promise这种代码逻辑比较复杂,类似常见算法中递归的过程,相对来说,代码的可读性比较差,你只需回想一下你第一次看递归代码的时候大概就知道这种过程了。
  2. 优点
    1. 是JS的原生特性,无需额外的库或抽象层。
    2. 可以在完成异步操作后执行一些操作。
  3. 缺点
    1. 代码的可读性和可维护性差,当多个回调嵌套时,就会出现传说中的 回调地狱
    2. 对错误处理变得复杂,因为每个回调都需要检查错误并传递给下一个回调。
    3. 不能返回多个参数,只能返回一个对象(有些资料对这个的解释是Callback是以参数的形式返回结果,但是并不准确,参考JS官方文档以及javascript - How do you properly return multiple values from a Promise? - Stack Overflow等内容,所谓的参数应该是一个参数,或者说是参数就是对象)
  4. 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

  1. Promise 其实就是一种封装的异步操作结果的对象。
  2. 三种状态
    1. pending,等待
    2. fulfilled,已成功
    3. rejected,已失败
  3. 优点:
    1. 可以采用同步的方式编写异步代码,因为异步操作结果已经被封装成了Promise,这样可以避免回调地狱。
    2. Promise对象本身是用链式而不是回调的方式调用,利用链式调用可以组合多个异步操作,并且可以用then 或者 catch操作来处理异步操作结果成功或者失败的情况。
    3. 比较灵活,可以用all方法等待所有异步操作的完成,也可以用race方法来获取最先完成的异步操作的结果。
  4. 缺点
    1. 因为做了一定程度的封装,用对象来存储异步操作的结果,其实就会消耗一些额外的内存和性能。
    2. 违背异步非阻塞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))。
    3. 也是只能返回一个对象。
  5. 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的一些参考资料,有需要的可以看看。

  1. OpenHarmony 源码解析之NAPI框架内部实现分析-51CTO.COM
  2. [三方库移植之NAPI开发1]—Hello OpenHarmony NAPI - 知乎 (zhihu.com)
  3. ace_napi: Development framework for extending the JS Native Module | 原生模块扩展开发框架 (gitee.com)
  4. vendor_unionman: 该仓库托管广东九联科技股份有限公司厂商驱动及配置文件 - Gitee.com
  5. 写一个N-API没那么难? - 知乎 (zhihu.com)
  6. 为JS写C++扩展,Napi第一步_napi.h_番茄V王子的博客-CSDN博客
  7. c++ - How to save an asynchronous callback for later using node-addon-api / napi - Stack Overflow
  8. 三方库移植之NAPI开发–异步调用:Callback&Promise(四)-51CTO.COM
  9. 箭头函数表达式 - JavaScript |多核 (mozilla.org)
  10. What are the pros and cons of using promises instead of callbacks? - Best Interview Question
  11. asynchronous - Why use promise or async/await on child processes in Node.js? - Stack Overflow
  12. How to use promises - Learn web development | MDN (mozilla.org)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_267638.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Telink之标准SDK的介绍_1

前提:常见的项目架构:应用层----》驱动层----》硬件层 1、软件组织架构 顶层⽂件夹( 8 个): algorithm,application,boot,common,drivers,proj_lib,stack,v…

HBase常用Shell命令

HBase提供了一个非常方便的命令行交互工具HBase Shell。通过HBase Shell,HBase可以与MySQL命令行一样创建表、索引,也可以增加、删除和修改数据,同时集群的管理、状态查看等也可以通过HBase Shell实现。 一、数据定义语言 数据定义语言&…

LeetCode 1599. Maximum Profit of Operating a Centennial Wheel【数组,模拟】中等

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…

[ 攻防演练演示篇 ] 利用 shiro 反序列化漏洞获取主机权限

🍬 博主介绍 👨‍🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…

ATool软件使用实验(22)

实验目的 1、学习ATool软件监控主机行为的原理; 2、学习利用ATool软件监控可疑进程的行为; 3、学习利用ATool软件实现对本机进行文件、注册表管理; 4、学习利用ATool软件实现对本机进行内核模块信息和HOOK信息查看。 预备知识 ATool是针…

测试按方向的分类

按方向分(都是在系统测试阶段测试的) 功能测试:举例说明什么是功能 性能测试 ①压力测试:不断地增加压力,从而找到系统的极限 ②负载测试:系统在极限工作条件下,最多能持续多久——可能发生内存泄漏/溢出,导…

Appium+Python连接真机、跳过登录页、Unexpected error while obtaining UI hierarchy问题

Appium连接真机 使用数据线连接电脑,然后选择文件传输方式 打开手机设置拉至底部,点击关于手机,连续点击7次版本号打开开发者模式 点击设置中的系统与更新,找到开发者选项----> 打开USB调试即可 在终端中输入adb devices确定…

案例解读| 从集中告警平台发展趋势看城商行如何落地数字化转型(二)

上期我们以具体案例入手,分享了集中告警平台到底应该与集中监控平台解耦还是紧绑定等问题。这一期依旧从具体案例切入,跟大家一起探索下告警与服务台的对接过程,以及这个过程中可能产生的问题。上期内容,一键回顾不迷路→案例解读…

angular技术(持续更新)

css类绑定[class.color-blue]"isBlue()" 如果isBlue()返回为true 这里使用color-blue的class样式style样式绑定[style.background-color]"canclick ? blue: red" 组件与模块模块的元数据*declarations: 用于指定属于这个模块的视图类(View Cla…

YOLOV5中添加CBAM模块详解——原理+代码

目录一、前言二、CAM1. CAM计算过程2. 代码实现3. 流程图三、SAM1. SAM计算过程2. 代码实现3. 流程图四、YOLOv5中添加CBAM模块参考文章一、前言 由于卷积操作通过融合通道和空间信息来提取特征(通过NNNNNN的卷积核与原特征图相乘,融合空间信息&#xff…

代码随想录-51-110.平衡二叉树

目录前言题目1.求高度和深度的区别节点的高度节点的深度2. 本题思路分析:3. 算法实现4. pop函数的算法复杂度5. 算法坑点前言 在本科毕设结束后,我开始刷卡哥的“代码随想录”,每天一节。自己的总结笔记均会放在“算法刷题-代码随想录”该专…

学习笔记:基于SpringBoot的牛客网社区项目实现(二)之Spring MVC入门

1.1 函数的返回值为空,因为可以使用response对象向浏览器返回数据。声明了request对象和response对象,dispatcherservlet自动将这两个对象传入 RequestMapping("/http")public void http(HttpServletRequest request, HttpServletResponse re…

不会吧,难道真的有程序员不知道怎么接单赚钱吗?

随着大环境逐渐转好,跳槽、新工作、兼职等等机会都浮出水面。抛开跳槽、新工作不谈,今天就专门来说说程序员接单赚钱有哪些靠谱的平台。 首先分享一波关于接私活有哪些注意事项,给大家提个醒,避免盲目入坑。 一、程序员接单须知…

深度学习知识点全面总结_深度学习总结

深度学习知识点全面总结_深度学习总结 神经网络与深度学习结构(图片选自《神经网络与深度学习》一邱锡鹏) 目录 常见的分类算法 一、深度学习概念 1.深度学习定义 2.深度学习应用 3.深度学习主要术语 二、神经网络基础 1. 神经网络组成 感知机 多层感知机 3.前向传播…

复位和时钟控制(RCC)

目录 复位 系统复位 电源复位 备份区复位 时钟控制 什么是时钟? 时钟来源 二级时钟源: 如何使用CubeMX配置时钟 复位 系统复位 当发生以下任一事件时,产生一个系统复位:1. NRST引脚上的低电平(外部复位) 2. 窗口看门狗计数终止(WWD…

项目实战典型案例27——单表的更新接口有9个之多

单表的更新接口有9个之多一:背景介绍环境准备引入pom依赖配置数据库连接mybatis配置文件Mybatis的配置类编写通用的更新语句可以覆盖的更新接口暂时无法覆盖的接口测试四:总结五:升华一:背景介绍 本篇博客是对项目开发中出现的单…

197.Spark(四):Spark 案例实操,MVC方式代码编程

一、Spark 案例实操 1.数据准备 电商网站的用户行为数据,主要包含用户的 4 种行为:搜索,点击,下单,支付 样例类: 2. Top10 热门品类 先按照点击数排名,靠前的就排名高;如果点击数相同,再比较下单数;下单数再相同,就比较支付数。 我们有多种写法,越往后性能越…

k8s学习之路 | k8s 工作负载 ReplicaSet

文章目录1. ReplicaSet 基础概念1.1 RS 是什么?1.2 RS 工作原理1.3 什么时候使用 RS1.4 RS 示例1.5 非模板 Pod 的获得1.6 编写 RS1.7 使用 RS1.8 RS 替代方案2. ReplicaSet 与 ReplicationController2.1 关于 RS、RC2.2 两者的选择器区别2.3 总结1. ReplicaSet 基础…

yii2项目使用frp https2http插件问题

yii2内网项目,使用frp进行内网穿透,使用 https2http插件把内网服务器http流量转成https,会存在一个问题:当使用 $this->redirect(...) 或 $this->goHome() (其实用的也是前者)等重定向时,…

物联网毕设 -- 智能厨房监测系统(改)

前言 在家庭生活中,厨房是必不可少的,所以厨房的安全问题关乎着我们大家的生命,所以提出智能厨房监测系统,目的就是为我们减少不必要的安全问题 ⚠️⚠️(本文章仅提供思路和实现方法,并不包含代码&#x…