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

这篇具有很好参考价值的文章主要介绍了开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

前言——系列介绍

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

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

MindMap

鸿蒙 napi,嵌入式,OpenHarmony,harmonyos,开源,学习

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,嵌入式,OpenHarmony,harmonyos,开源,学习

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的一些参考资料,有需要的可以看看。文章来源地址https://www.toymoban.com/news/detail-793857.html

  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)

到了这里,关于开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • HarmonyOS ArkUI实战开发-NAPI 加载原理(下)

    上一节笔者给大家讲解了 JS 引擎解释执行到  import  语句的加载流程,总结起来就是利用  dlopen()  方法的加载特性向  NativeModuleManager  内部的链接尾部添加一个  NativeModule ,没有阅读过上节文章的小伙伴,笔者强烈建议阅读一下,本节笔者继续给大家讲解 JS 调用 C++ 方法

    2024年04月27日
    浏览(31)
  • Harmony鸿蒙南向驱动开发流程

    HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理、驱动消息机制和配置管理。并以组件化驱动模型作为核心设计思路,让驱动开发和部署更加规范,旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的驱动

    2024年04月27日
    浏览(28)
  • OpenHarmony鸿蒙南向开发案例:【智能门铃】

    样例简介 智能门铃通过监控来访者信息,告诉主人门外是否有人按铃、有陌生人靠近或者无人状态。主人可以在数字管家中远程接收消息,并根据需要进行远程取消报警和一键开锁。同时,也可以通过室内屏幕获取门外状态。室内屏幕显示界面使用DevEco Studio 编写的js应用,

    2024年04月26日
    浏览(31)
  • Harmony鸿蒙南向驱动开发-RTC接口使用

    功能简介 RTC(real-time clock)为操作系统中的实时时钟设备,为操作系统提供精准的实时时间和定时报警功能。当设备下电后,通过外置电池供电,RTC继续记录操作系统时间;设备上电后,RTC提供实时时钟给操作系统,确保断电后系统时间的连续性。 运作机制 在HDF框架中,

    2024年04月13日
    浏览(69)
  • Harmony鸿蒙南向驱动开发-ADC接口使用

    ADC(Analog to Digital Converter),即模拟-数字转换器,可将模拟信号转换成对应的数字信号,便于存储与计算等操作。除电源线和地线之外,ADC只需要1根线与被测量的设备进行连接,其物理连线如图1所示: 图 1  ADC物理连线示意图 ADC接口定义了完成AD转换的通用方法集合,包括

    2024年04月12日
    浏览(40)
  • Harmony鸿蒙南向驱动开发-PWM接口使用

    功能简介 PWM即脉冲宽度调制(Pulse Width Modulation)的缩写,是一种对模拟信号电平进行数字编码并将其转换为脉冲的技术。 PWM接口定义了操作PWM设备的通用方法集合,包括: PWM设备句柄获取和释放 PWM周期、占空比、极性的设置 PWM使能和关闭 PWM配置信息的获取和设置 基本概

    2024年04月13日
    浏览(32)
  • OpenHarmony鸿蒙南向开发案例:【智能猫眼(基于3518开发板)】

    样例简介 本Demo是基于Hi3518开发板,使用开源OpenHarmony开发的RTSP协议流媒体应用。达到将Hi3518开发板中摄像头获取的数据通过RTSP协议传输到手机并显示 。 rtsp实现可参考文档:openharmony_1.0.1实现RTSPServer 运行效果 样例原理 如上图所示,手机播放3518摄像头采集的视频数据。 工

    2024年04月28日
    浏览(51)
  • Harmony鸿蒙南向驱动开发-I3C接口使用

    功能简介 I3C(Improved Inter Integrated Circuit)总线是由MIPI Alliance开发的一种简单、低成本的双向二线制同步串行总线。 I3C是两线双向串行总线,针对多个传感器从设备进行了优化,并且一次只能由一个I3C主设备控制。相比于I2C,I3C总线拥有更高的速度、更低的功耗,支持带内中

    2024年04月12日
    浏览(29)
  • 从何着手OpenHarmony?从这里开始认识嵌入式开源鸿蒙操作系统

    首先,我们需要知道HarmonyOS与OpenHarmony是不同的概念,我们需要知道它们的区别:         HarmonyOS是华为独家开发的,但华为在2020、2021年分两次 将HarmonyOS的基础能力全部捐献给了开放原子开源基金会,形成了OpenHarmony开源项目 ,华为对开源鸿蒙没有控制权,当然华为仍将

    2024年02月04日
    浏览(44)
  • 基于MVS的三维重建算法学习笔记(一)— MVS三维重建概述与OpenMVS开源框架配置

    本人书写本系列博客目的是为了记录我学习三维重建领域相关知识的过程和心得,不涉及任何商业意图,欢迎互相交流,批评指正。 MVS(多视点立体视觉,Multi-view stereo)能够单独从图像中构造出高度细节化的3D模型,采集一个庞大的图像数据集,用其来构建出一个用来解析

    2024年01月15日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包