最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

初識(shí) NAPI-RS

2023-04-28 10:51 作者:支付寶體驗(yàn)科技  | 我要投稿

?????♀? 編者按:NAPI-RS 是一個(gè)使用 Rust 構(gòu)建預(yù)編譯 Node.js 原生擴(kuò)展的框架,本文作者是螞蟻集團(tuán)前端工程師伊北,帶大家初步了解 NAPI-RS,包括如何接入、一些用法、工作機(jī)制以及要注意的點(diǎn)等等,歡迎一起交流~

  • 建議查閱 napi-rs 官網(wǎng) https://napi.rs/

  • 對(duì)于更深入的部分理解,可閱讀?https://juejin.cn/post/7202541740934709303

如何接入

目前提供:

  • 提供自動(dòng)化的多平臺(tái)編譯發(fā)布的解決方案:使用?@napi-rs/cli?初始化項(xiàng)目,或者通過(guò)?napi-rs/package-template?從 github 模板初始化。

  • 提供?全平臺(tái)自動(dòng)化跨平臺(tái)編譯?(https://napi.rs/docs/cross-build/summary)的解決方案,示例參考 https://github.com/napi-rs/cross-build,提供基于 GitHub Linux CI 構(gòu)建跨平臺(tái)(橫跨 Windows、macOS、Linux、Android 等不同 os、不同 libc、不同 arch 指令集平臺(tái)),通過(guò) zig + cargo-xwin 實(shí)現(xiàn)。

  • 提供 cli 覆蓋本地開(kāi)發(fā)和?github CI?(可選)全流程。

生成的項(xiàng)目的目錄結(jié)構(gòu)


自動(dòng)按平臺(tái)分發(fā)安裝包

不同于 node-gyp 本地編譯 C++ 包的方式,napi-rs 框架設(shè)計(jì)為

  • 為各個(gè) triples 分配一個(gè) npm 包,并指定 os、cpu、libc 的值,按照對(duì)應(yīng)的 triples 提前編譯好對(duì)應(yīng)的 .node 文件,并作為 main 字段導(dǎo)出。

  • 主包中,將所有平臺(tái)的包作為 optionalDependencies 進(jìn)行聲明。

  • 當(dāng)用戶安裝主包時(shí),會(huì)安裝當(dāng)前機(jī)器對(duì)應(yīng)的 optionalDependencies 下來(lái)。比如在 mac 下安裝?@node-rs/xxhash,則會(huì)同時(shí)安裝?@node-rs/xxhash-darwin-arm64?包下來(lái)。


  • 用戶通過(guò)導(dǎo)入主包的形式進(jìn)行使用,主包的 index.js 中會(huì)判斷好 os、arch、libc 類型,來(lái)決定 require 哪個(gè)平臺(tái)包(或者是本地 .node 文件)

一些用法

自動(dòng)生成 d.ts

  • napi-rs 提供了額外的類型支持,以便生成跟 ts 對(duì)應(yīng)的上的類型文件。

  • 將對(duì)應(yīng)的 Rust 代碼中的類型生成相應(yīng)的 .d.ts 文件,為 binding 庫(kù)提供類型支持。

命名轉(zhuǎn)換

  • 默認(rèn)將 Rust 風(fēng)格的蛇形轉(zhuǎn)為駝峰風(fēng)格,hello_world?->?helloWorld

  • 通過(guò)?#[napi(js_name = "yourFnName")]?修改宏的行為來(lái)自定義 js 中變量名

JS 類型映射

bindgen_prelude

JS 的基本類型的映射支持如下,具體可見(jiàn) https://napi.rs/docs/concepts/values

  • Undefined

  • Null

  • Number/BigInt

  • String

  • Boolean

  • Buffer

  • Object

  • Array

  • TypedArray

關(guān)于 JSValue 可見(jiàn) https://napi.rs/docs/compat-mode/concepts/js-values

工作機(jī)制

模塊注冊(cè)

#[napi] 宏自動(dòng)編譯生成對(duì)應(yīng)的模塊導(dǎo)出,相比于 v1,v2 版本通過(guò)宏編譯 + 約定的方式簡(jiǎn)化了寫法。

上述代碼的目的是將?plus_100導(dǎo)出并暴露給 JS 使用。我們來(lái)看看 napi-rs 的宏是怎么編譯這段代碼的??吹捻樞蚴菑南峦系姆催^(guò)來(lái)。

補(bǔ)充 FFI 和 ABI 的基本概念

FFI(Foreign Function Interface/外部函數(shù)接口)和 ABI(Application Binary Interface/應(yīng)用程序二進(jìn)制接口)是兩個(gè)相關(guān)但不同的概念,它們都涉及到不同語(yǔ)言或系統(tǒng)之間的函數(shù)調(diào)用和數(shù)據(jù)交換。

FFI 是實(shí)現(xiàn)不同語(yǔ)言間交互的接口或者說(shuō)是機(jī)制,允許不同語(yǔ)言編寫的程序互相通信和調(diào)用,且不需要額外的轉(zhuǎn)換或者序列化/反序列化。

ABI 則類似規(guī)范/協(xié)議,定義了不同語(yǔ)言或系統(tǒng)之間的函數(shù)調(diào)用和數(shù)據(jù)交換的細(xì)節(jié),例如函數(shù)參數(shù)和返回值的傳遞方式、寄存器和棧的使用、可執(zhí)行文件的格式、虛擬地址空間布局等等。

FFI 依賴于 ABI 來(lái)實(shí)現(xiàn)跨語(yǔ)言或跨系統(tǒng)的函數(shù)調(diào)用,F(xiàn)FI 通過(guò) ABI 來(lái)確認(rèn)函數(shù)的簽名,包括函數(shù)的名稱、參數(shù)類型、返回類型,以及函數(shù)的地址(即函數(shù)在內(nèi)存中的位置)。

FFI 可以看作是 ABI 的一個(gè)高層抽象,它隱藏了 ABI 的復(fù)雜性,提供了一個(gè)簡(jiǎn)單易用的接口。


而?register_module_export?會(huì)在 addon 程序被初次載入時(shí):

  • 將函數(shù)的指針?lè)诺揭粋€(gè) local thread queue 中

  • 在 Node 初始化 addon 后,會(huì)調(diào)用 addon 中?napi_register_module_v1?函數(shù),傳入 env 和 exports 對(duì)象

  • NAPI-RS 在?napi_register_module_v1?中拿到 env 后遍歷 local thread queque 中存儲(chǔ)的函數(shù)并傳入?env,進(jìn)而得到?register_js_function?等 register_xxx 注冊(cè)的值(函數(shù)/常量/Class)等,掛載到 exports 對(duì)象上

這就是初始化的完整過(guò)程。更多可見(jiàn)源碼?napi/src/bindgen_runtime/module_register.rs?中的實(shí)現(xiàn)。

調(diào)用順序

Node 和 Rust 互相調(diào)用建立在 C ABI 基礎(chǔ)上的 FFI 調(diào)用

Node.js 中調(diào)用 plus100 -> 調(diào)用到 FFI 函數(shù) __napi__plus_100 -> 提取參數(shù)給 Rust fn plus_100

要注意的點(diǎn)

包名修改

強(qiáng)烈建議直接使用?napi rename?命令執(zhí)行:會(huì)直接更新模板里所有跟 pkg.json#name 和 pkg.json#napi.name 相關(guān)的變量命名。
  • 初始化項(xiàng)目時(shí),后續(xù)若要修改 root 下 package.json 中包名(name),需要將 npm 目錄下所有的平臺(tái)產(chǎn)物包名也要同步修改。

  • package.json 下的?napi.name?修改時(shí),會(huì)影響生成的 .node 產(chǎn)物命名,需要修改掉:

    • index.js 中針對(duì)不同平臺(tái)時(shí) require local 和 require 對(duì)應(yīng) npm 包名的規(guī)則

  • CI 配置中的 env.app_name,影響到 job 間持久化產(chǎn)物的規(guī)則,類似 https://github.com/vagusX/rs-html-text-content/actions/runs/4459416487/jobs/7831855982

  • 平臺(tái)產(chǎn)物包的 main 字段以及 files 字段

Rust Eum 與 TS Enum 不對(duì)等

js 中沒(méi)有 Enum,而 TS 中 enum 長(zhǎng)這樣。

Rust 的 enum 通過(guò) napi 導(dǎo)出到 js 后,跟 TS 中 enum 的區(qū)別是:缺少 TS 中?reverse mapping 的行為

JS 和 Rust 之間的 Object 轉(zhuǎn)換成本比其他基本類型高

每次調(diào)用?Object.get("key")?實(shí)際上都會(huì)分派到 Node,包括兩個(gè)步驟:fetch value、將 JS 值轉(zhuǎn)為 Rust 值,調(diào)用?Object.set("key", v)?也是一樣。同樣的 JS Array 也是一樣。推薦將對(duì)應(yīng)的參數(shù)通過(guò)?struct定義好,這樣避免直接使用?Object類型。

TypedArray 可在 Node 和 Rust 間共享數(shù)據(jù)

同理 Buffer 也是 Unit8Array 的子類,具體參見(jiàn) https://napi.rs/docs/concepts/typed-array

高級(jí)用法

  • Rust 類型中?u64,?u128,?i128,轉(zhuǎn)為 JS 需要配置 napi6(node 10.7) 開(kāi)啟 BigInt 支持,開(kāi)啟方式:在?Cargo.toml中開(kāi)啟?features = ["napi6"]。(默認(rèn)為 napi4)

  • Types Overwrite:使用字符串作為 napi 宏的參數(shù),達(dá)到覆蓋掉自動(dòng)生成類型的效果。可以覆蓋參數(shù)、返回值、struct?中的字段

  • Async/Await:配合?tokio?(https://tokio.rs/) 一起使用

    • Rust 傳給 js 一個(gè) Promise 作為結(jié)果:

    • js 傳給 Rust 一個(gè) Promise ?作為參數(shù):高級(jí)用法,但是可以不用

  • 使用?AsyncTask/Task?(https://napi.rs/docs/concepts/async-task)(前者是后者的 wrapper,讓 js 可以調(diào)用):Task 讓我們具備在 libuv 線程池中異步執(zhí)行任務(wù)(如一些高 cpu 耗時(shí)任務(wù)),而不阻塞 Node.js 的 Event Loop。

  • External(https://napi.rs/docs/concepts/external):在 JS 中,調(diào)用后產(chǎn)生一個(gè)對(duì)象以表示 Native 值,該對(duì)象上有一些方法可以再跟 Native 交互。

如何調(diào)試

調(diào)試宏

vscode rust-analyzer 自帶

調(diào)試源碼

以下部分展示的是使用同一個(gè) js 入口文件進(jìn)行調(diào)試

調(diào)試 nodejs 部分

使用標(biāo)準(zhǔn)的 vscode js debugger 配置即可,或者創(chuàng)建一個(gè) JavaScript Debug Terminal

調(diào)試 Rust 部分

需要先構(gòu)建出一個(gè)支持調(diào)試的產(chǎn)物,再使用 lldb 進(jìn)行調(diào)試

我將它編寫為兩個(gè)配置文件,分別是 .vscode/tasks.json 和 .vscode/launch.json


初識(shí) NAPI-RS的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
缙云县| 姜堰市| 宣化县| 临江市| 通城县| 老河口市| 屏山县| 内乡县| 成安县| 宽甸| 都匀市| 怀来县| 新源县| 北京市| 大石桥市| 含山县| 朝阳市| 集安市| 陕西省| 剑河县| 遵义市| 从江县| 陆河县| 鄂州市| 南城县| 赣州市| 临猗县| 佛教| 眉山市| 衡阳市| 巴林左旗| 嘉黎县| 伊川县| 定兴县| 灵山县| 临邑县| 南皮县| 揭阳市| 邯郸县| 南乐县| 新营市|