当前位置: 首页 > news >正文

网站背景图片素材浙江城乡住房建设厅网站

网站背景图片素材,浙江城乡住房建设厅网站,企业seo网站推广,python3 网站开发实例前言 近年来#xff0c;Rust的受欢迎程度不断上升。首先#xff0c;在操作系统领域#xff0c;Rust 已成为 Linux 内核官方认可的开发语言之一#xff0c;Windows 也宣布将使用 Rust 来重写内核#xff0c;并重写部分驱动程序。此外#xff0c;国内手机厂商 Vivo 也宣布…前言 近年来Rust的受欢迎程度不断上升。首先在操作系统领域Rust 已成为 Linux 内核官方认可的开发语言之一Windows 也宣布将使用 Rust 来重写内核并重写部分驱动程序。此外国内手机厂商 Vivo 也宣布使用 Rust 开发了名为“蓝河”的操作系统。除此之外Rust 在图形渲染、游戏开发、中间件开发、边缘计算、计算安全等领域也是遍地开花可以说Rust 正在以惊人的速度重塑着各个领域的发展让人不禁感叹 Rust 已经在重写万物了。 那回到前端领域正在进行一场构建工具的革命除了老牌的 Babel 竞争对手swc一些新兴的前端构建工具也都在使用 Rust 进行开发例如Turbopack、Parcel对标 Webpack 的Rspack对标 Vite 的Farm等等。所以对于广大前端同胞来说C/C 太难学习和掌握 Rust 是一个不错的选择虽然 Rust 也不见得容易许多它有着陡峭的学习曲线但它或许是我们突破闭塞的前端区间的一把钥匙帮助我们打开通往新世界的大门。 锈化开发工具的方式 虽说 Rust 的学习曲线可能相对陡峭但笔者认为这是对于要全面掌握 Rust 这门语言而言的而我们学习语言的目的最重要的是掌握一项可以帮我们解决问题的技能因此对于 Rust 不需要抱有太多的恐惧和敬畏之心只需要摒除杂念立马开始学习 撸码剩下的就交给时间来慢慢积累经验。此外对于不是那么复杂应用来说熟悉 Rust 基本语法和数据结构翻过「所有权机制」和「生命周期」两座大山基本也足以应付了。 本文建立在读者已经有一定的 Rust 知识基础上对于 Rust 基本语法就不做赘述了。当前大部分前端研发都是在 Node 环境下进行的所以我们通过 Rust 来改造开发工具主要有两种形式 使用 WASM 的方式基于wasm-pack将 Rust 代码编译成 WASM以供 Node 调用 将 Rust 应用编译成 Node addons通过 Node API 的方式供 Node 调用可以基于napi-rs和neon来实现 在这两种方式的选择上主要取决于你是否需要完整地访问 Node APIWASM 出于安全性的考虑对于 Node 能力的调用存在限制那么此时就应该选择 Node addons 的方式了。而napi-rs和neon的选择的话napi-rs相对而言比较简单和轻量而且针对不同版本的 Node 不需要重新编译所以我们考虑选择napi-rs作为锈化开发工具的方式。 初识 NAPI-RS 我们可以通过 napi-rs 的开发工具 ****napi-rs/cli**以及项目模板来初始化一个应用这里推荐使用项目模板因为经过笔者的测试开发工具创建的项目内容上相较于模板比较落后对于后续深入使用上会造成一定的困惑。 从 napi-rs 项目模板内容上看可以发现项目结构完善工程化相关能力非常齐全提供了构建工具、测试用例编写、Github CI 工作流等等必须的能力我们只需要关注编码就可以了。 我们先来关注一下生成的 napi-rs 项目文件。从package.json和npm分析可以看出一个 napi-rs 项目主要是由主包和 npm 下的针对不同平台的编译构建结果子包组成napi-rs 会根据用户的配置将用户的 Rust 代码构建为不同平台下的 Node 扩展 binding 文件这些文件会放到 npm 下对应的平台目录中再由 package.json 中 main 字段指定导出用户在安装主包的时候会根据用户电脑情况加载对应构建结果子包。 {name: tarojs/parse-css-to-stylesheet-darwin-x64,version: 0.0.25,os: [darwin],cpu: [x64],main: parse-css-to-stylesheet.darwin-x64.node,files: [parse-css-to-stylesheet.darwin-x64.node],license: MIT,engines: {node: 10},repository: https://github.com/NervJS/parse-css-to-stylesheet } 而在主包入口index.js中将根据用户宿主平台加载对应的扩展文件。 ... switch (platform) {case win32:switch (arch) {case x64:localFileExisted existsSync(join(__dirname, parse-css-to-stylesheet.win32-x64-msvc.node))try {if (localFileExisted) {nativeBinding require(./parse-css-to-stylesheet.win32-x64-msvc.node)} else {nativeBinding require(tarojs/parse-css-to-stylesheet-win32-x64-msvc)}} catch (e) {loadError e}break...}break... } ... 从napi-rs/triples这个包中可以看到所有支持的平台列表而对于常规性的 Node 应用来说我们不需要构建这么多平台一般来说构建x86_64-apple-darwin、aarch64-apple-darwin、x86_64-pc-windows-msvc、x86_64-unknown-linux-gnu这四个平台也足够了这样也能减少 CI 的构建时间。 napi-rs 默认构建的平台是x86_64-apple-darwin、x86_64-pc-windows-msvc、x86_64-unknown-linux-gnu在这里可以看到所以为了增加 MAC Book M 系列电脑的支持我们需要增加aarch64-apple-darwin的配置可以在 package.json 中napi字段中添加配置如下 napi: {binaryName: taro,triples: {default: true,additional: [aarch64-apple-darwin]} }, 接下来就可以开始我们的编码之旅咯 基于 NAPI-RS 开发 Node 扩展 基于 napi-rs 开发 Node 扩展除了 Rust 编码本身外无非需要关注两种情况即 JavaScript 调用 Rust 和 Rust 调用 JavaScript。 JavaScript 调用 Rust 调用 Rust 函数 这是最常见的用法因为我们一般使用 Rust 开发 Node 扩展也是为了将一些 CPU 密集型任务的任务使用 Rust 来实现再暴露给 JS 来调用从而达到提升应用性能的目的最为常见的是 Rust 暴露方法给到 JS 调用通过项目模板生成的 napi-rs 示例也可以看到。 // src/lib.rs use napi_derive::napi;#[napi] pub fn plus_100(input: u32) - u32 {input 100 } 如上代码通过给plus_100函数添加#[napi]属性宏这样可以标记该函数表示该函数可以通过 N-API 在 Node.js 中调用在项目编译后的 typing 文件中我们能看到对应生成了 JS 函数. export function plus100(input: number): number 可以看到这里生成 JS 函数名是 napi-rs 自己的规则我们也可以自定义暴露的函数名通过js_name属性可以指定。 #[napi(js_name plus_100)] pub fn plus_100(input: u32) - u32 {input 100 } 当然除了暴露函数这一基本操作之外我们还可以暴露常量、对象、类、enum 等等给到 JS 侧去调用这些可以通过 napi-rs 的官方文档可以查阅到。 以 Object 作为参数 而在 JS 调用 Rust 编码中最需要关注的是调用函数时JS 侧给 Rust 传对象作为参数这里为了提升性能建议提前在 Rust 中定义好传递对象的数据结构在 JS 中以引入该数据结构定义规范数据传递即可。 // 定义好数据结构 // napi(object) 表示紧随其后的 struct 结构体将通过 N-API 以 JavaScript 对象的形式暴露出去 #[napi(object)] pub struct Project {pub project_root: String,pub project_name: String,pub npm: NpmType,pub description: Option,pub typescript: Option,pub template: String,pub css: CSSType,pub auto_install: Option,pub framework: FrameworkType,pub template_root: String,pub version: String,pub date: Option,pub compiler: Option,pub period: PeriodType, } JS 中调用 // 函数定义其中 Project 由 Rust binding 中暴露 export function createProject(conf: Project)// 函数调用 createProject({projectRoot: projectDir,projectName,template,npm,framework,css: this.conf.css || CSSType.None,autoInstall: autoInstall,templateRoot: getRootPath(),version: getPkgVersion(),typescript: this.conf.typescript,date: this.conf.date,description: this.conf.description,compiler: this.conf.compiler,period: PeriodType.CreateAPP, }) Rust 调用 JavaScript 而 Rust 中也可以调用 JS 提供的方法这在做 Node 开发工具的时候非常有用因为有时候我们需要读取开发人员的配置代码给到 Rust 调用其中就可能会遇到 Rust 调用 JavaScript 中函数的情况。 一个调用 JS 函数的简单例子 在 napi-rs 中调用 JS 函数主要通过ThreadsafeFunction来实现请看例子 #[napi] pub fn call_threadsafe_function(callback: ThreadsafeFunction) - Result() {for n in 0..100 {let tsfn callback.clone();thread::spawn(move || {tsfn.call(Ok(n), ThreadsafeFunctionCallMode::Blocking);});}Ok(()) } 在上述例子中call_threadsafe_function函数接受了一个类型为ThreadsafeFunctionu32的参数这表明call_threadsafe_function被编译为 JS 函数后将接受一个回调函数作为参数而该回调函数的有效参数为u32即number类型而在call_threadsafe_function函数体中通过thread::spawn开辟子线程以阻塞的方式调用这个传入的回调函数。 通过ThreadsafeFunction的call方法可以调用到传入的 JS 回调函数但是我们会发现它拿不到返回值如果我们需要获取到 JS 回调函数的返回值时我们需要使用call_with_return_value和call_async两个方法。 获取 JS 函数的返回值 对比call与call_with_return_value的实现可以看出call_with_return_value比call多一个回调函数参数并且可以指定 JS 回调函数返回值的类型并且该类型需要满足FromNapiValue这个 trait因为call_with_return_value在处理 JS 回调函数时会调用它的from_napi_value方法将 JS 数据转为 Rust 的数据类型。 // https://github.com/napi-rs/napi-rs/blob/main/crates/napi/src/threadsafe_function.rs#L428 pub fn call(self, value: Result, mode: ThreadsafeFunctionCallMode) - Status {self.handle.with_read_aborted(|aborted| {if aborted {return Status::Closing;}unsafe {sys::napi_call_threadsafe_function(self.handle.get_raw(),Box::into_raw(Box::new(value.map(|data| {ThreadsafeFunctionCallJsBackData {data,call_variant: ThreadsafeFunctionCallVariant::Direct,callback: Box::new(|_d: Result| Ok(())),}}))).cast(),mode.into(),)}.into()}) }pub fn call_with_return_value Result()(self,value: Result,mode: ThreadsafeFunctionCallMode,cb: F, ) - Status {self.handle.with_read_aborted(|aborted| {if aborted {return Status::Closing;}unsafe {sys::napi_call_threadsafe_function(self.handle.get_raw(),Box::into_raw(Box::new(value.map(|data| {ThreadsafeFunctionCallJsBackData {data,call_variant: ThreadsafeFunctionCallVariant::WithCallback,callback: Box::new(move |d: Result| {d.and_then(|d| D::from_napi_value(d.0.env, d.0.value).and_then(cb))}),}}))).cast(),mode.into(),)}.into()}) } call_with_return_value的使用方式如下 #[napi] pub fn call_threadsafe_function(callback: ThreadsafeFunction) - Result() {callback.call_with_return_value(Ok(1), ThreadsafeFunctionCallMode::Blocking, move |result: u32| {println!(callback: {result:?});Ok(())});Ok(()) } 可以看出JS 回调函数的返回值是在call_with_return_value的第三个回调函数参数中获取到的这就导致如果我们需要依赖这个 JS 函数返回值的话我们后续的逻辑代码只能写在call_with_return_value的第三个回调函数参数中对我们的代码逻辑书写造成诸多不便代码可读性降低所以推荐使用call_async方法来执行 JS 函数并获取参数。 使用call_async获取 JS 函数返回值 从call_async的实现可以看出它首先使用了tokio创建了一个 one-shot 通道让 JS 函数以不阻塞的方式异步运行并在执行完成后通过sender 发送操作结果而使用receiver进行等待执行结果并将结果返回同时要使用call_async方法需要在Cargo.toml中为napi依赖打开tokio_rt特性。 #[cfg(feature tokio_rt)] pub async fn call_async(self, value: Result) - Result {let (sender, receiver) tokio::sync::oneshot::channel::();self.handle.with_read_aborted(|aborted| {if aborted {return Err(crate::Error::from_status(Status::Closing));}check_status!(unsafe {sys::napi_call_threadsafe_function(self.handle.get_raw(),Box::into_raw(Box::new(value.map(|data| {ThreadsafeFunctionCallJsBackData {data,call_variant: ThreadsafeFunctionCallVariant::WithCallback,callback: Box::new(move |d: Result| {sender.send(d.and_then(|d| D::from_napi_value(d.0.env, d.0.value))).map_err(|_| {crate::Error::from_reason(Failed to send return value to tokio sender)})}),}}))).cast(),ThreadsafeFunctionCallMode::NonBlocking.into(),)},Threadsafe function call_async failed)})?;receiver.await.map_err(|_| {crate::Error::new(Status::GenericFailure,Receive value from threadsafe function sender failed,)}).and_then(|ret| ret) } 可见call_async使用时将引入 Rust 的异步编程我们可以使用async/await关键字来进行调用使用方式如下 #[napi] pub async fn call_threadsafe_function(callback: ThreadsafeFunction) - Result {let result match callback.call_async::(Ok(1)).await {Ok(res) res,Err(e) {println!(Error: {}, e);0}};println!(result: {result:?});Ok(result) } 此时生成的 JS 函数定义为如下可以看出callThreadsafeFunction变成了一个异步函数 export function callThreadsafeFunction(callback: (err: Error | null, value: number) any): Promisenumber 所以在 JS 中调用方式及输出结果为 const result await callThreadsafeFunction((err, value) {return value 1 }) console.log(result)// 输出结果 // result: 2 // 2 正确处理 JS 函数的返回值 从前面call_async的实现可以看出call_async返回的数据也即 JS 函数返回值需要满足如下泛型约束D: static FromNapiValue而 napi-rs 默认会为数值、字符串、布尔等基本 JS 数据类型实现FromNpiValuetrait但是如果我们的 JS 回调想要返回一个对象时则需要自己手动实现FromNpiValuetrait这样可以让call_async获取到 JS 返回数据时自动调用FromNpiValuetrait 的from_napi_value方法将 JS 返回数据转换为 Rust 的数据格式以下是一个简单的示例。 假如需要在 Rust 调用一个 JS 函数JS 函数会返回一个对象包含三个字段 {setPageName?: string,changeExt?: boolean,setSubPkgName?: string } 我们需要在 Rust 中获取到返回的对象并转为 Rust 数据那么首先我们可以定义一个类似的数据结构 #[derive(Debug)] pub struct JSReturnObject {pub set_page_name: Option,pub change_ext: Option,pub set_sub_pkg_page_name: Option, } 同时为它实现FromNpiValuetrait 就可以了 impl FromNapiValue for JSReturnObject {unsafe fn from_napi_value(env: napi_env, napi_val: napi_value) - Result {let obj JsObject::from_napi_value(env, napi_val)?;let mut js_return_object JSReturnObject {set_page_name: None,change_ext: None,set_sub_pkg_page_name: None,};let has_set_page_name obj.has_named_property(setPageName)?;let has_change_ext obj.has_named_property(changeExt)?;let has_set_sub_pkg_page_name obj.has_named_property(setSubPkgName)?;if has_set_page_name {js_return_object.set_page_name Some(obj.get_named_property::(setPageName)?);}if has_set_sub_pkg_page_name {js_return_object.set_sub_pkg_page_name Some(obj.get_named_property::(setSubPkgName)?);}if has_change_ext {js_return_object.change_ext Some(obj.get_named_property::(changeExt)?);}Ok(js_return_object)} } 在上述代码中先调用JsObject::from_napi_value方法将传入数据转为JsObject然后调用 JsObject的has_named_property方法获取到对应的属性值经过处理后可以构建出JSReturnObject结构体数据并进行返回。而使用的时候为call_async指定泛型参数类型为JSReturnObject接下来就可以获取到 JS 返回值进行处理了。 let result: JSReturnObject js_handler.call_async(Ok(options.clone())).await.with_context(|| format!(模板自定义函数调用失败: {}, file_relative_path))?; 使用 VSCode 进行调试 我们可以使用 VSCode 来调试我们的 napi-rs 应用我们可以参考Taro 项目在项目的 .vscode 目录下新增 launch.json 配置如下 {// Use IntelliSense to learn about possible attributes.// Hover to view descriptions of existing attributes.// For more information, visit: https://go.microsoft.com/fwlink/?linkid830387version: 0.2.0,configurations: [{type: lldb, // 调试器类型这里指定为lldb通常用于C/C/Rust等语言request: launch, // 请求类型可以是launch或attachlaunch表示启动一个新的调试会话name: debug-init, // 配置名称显示在VS Code的启动配置下拉菜单中sourceLanguages: [rust], // 指定源码语言此处为Rustprogram: node, // 要调试的程序这里是指Node.js的可执行文件args: [// 程序参数这里指定了使用node运行taro-cli包的初始化命令创建一个名为test_pro的新项目${workspaceFolder}/packages/taro-cli/bin/taro,init,test_pro],cwd: ${workspaceFolder}, // 当前工作目录这里指工作区根目录preLaunchTask: build binding debug, // 调试前需要执行的任务的名称这里指定了一个任务以在调试前构建项目postDebugTask: remove test_pro // 调试后需要执行的任务的名称此处指定了一个任务以在调试后清理或删除test_pro项目},] } 在上述配置中指定调试器类型为lldb启动一个新的调试会话来调试我们用 Rust 编写的程序该程序主要通过 Node.js 来执行一个初始化新项目 test_pro 的命令在调试开始前后会飞别执行 Rust binding 的构建以及 test_pro 项目的删除。 然后在要调试的代码处添加断点然后执行调试即可。 构建发布 napi-rs 的项目模板默认基于 Github Action 来实现自动构建产物及发布并且已经有相当完整的配置了从Github Action配置文件中可以看到 CI 具体执行的任务CI 任务首先会执行 package.json 中的构建命令构建出各个端的 binding并会actions/upload-artifactv3action 将构建产物上传然后会对构建产物执行相关测试测试通过后会将构建产物下载下来并执行artifacts命令将构建产物移动到目的文件夹下最后会进行发布当 git 提交信息为semver规范版本号时将会触发 CI 发布将包发到 NPM 中去。 $ git commit -m 0.0.1 前面提到我们一般只需要针对x86_64-apple-darwin、aarch64-apple-darwin、x86_64-pc-windows-msvc、x86_64-unknown-linux-gnu这四个平台进行构建所以我们可以调整 Github Action 配置去掉不需要构建的平台以提升 CI 速度。 此外当我们有特殊需求的时候例如不需要重新生成胶水 JS 代码、需要将构建产物移动到其他目录默认是当前目录下的 npm 目录下等等可以查看napi-rs/cli的文档进行相应调整。 不需要重新生成胶水 JS 代码可以通过在napi build命令下添加--no-js实现 scripts: {...build: napi build --platform --release --no-js --dts binding.d.ts,build:debug: napi build --platform --no-js --dts binding.d.ts... } 需要将构建产物移动到其他目录可以通过在napi artifacts命令下添加 --cwd 和 --npm-dir 参数来实现前者指定工作目录后者指定要移动的目录的相对路径 scripts: {...artifacts: napi artifacts --npm-dir ../../npm2 --cwd ./,... } 总结 Rust 在前端领域的应用无疑将成为未来的重要发展趋势随着越来越多的公司和团队开始投入到这一领域我们看到了 Rust 在前端研发生态构建中的独特优势和潜力Rust 的高效性和安全性使其成为优化 Node 工具的理想选择。本文简单介绍了如何使用 NAPI-RS 来开发、调试和发布 Node 扩展可以有效地优化我们的开发工具并提升其性能。 在未来我们可以预见 Rust 与前端结合的可能性将会更加广泛。随着 WebAssemblyWASM的发展我们可以期待 Rust 将在前端应用的性能优化、复杂应用的开发以及多线程等领域发挥更大的作用。同时Rust 的出色的内存管理和错误处理机制也将帮助前端开发者构建更加健壮、安全的应用。 当然Rust 与前端的结合并不仅仅限于性能优化Rust 的优秀特性如模式匹配、类型推断和零成本抽象也为前端开发带来了新的编程范式和思维方式这将有助于提升前端代码的可读性和可维护性为前端开发提供了新的思考角度和工具并可能引领前端开发进入一个全新的阶段。 作者京东零售 李伟涛 来源京东云开发者社区 转载请注明来源
http://www.hyszgw.com/news/95311.html

相关文章:

  • jsp和servlet网站开发简述网站建设基本流程
  • 可以用什么网站做mc官方高端网咖电脑配置
  • 蝌蚪窝一个释放做网站平面设计师求职网
  • html5网站报价明细谷歌seo服务
  • 青海网站建设价格低餐饮vi设计一套多少钱
  • 织梦网站地图插件utf-8有哪些网站做的比较好
  • 闵行区做网站公司做一手楼房的网站
  • php网站开发个人简历php响应式网站开发百度云
  • 有成功案例的网站jsp网站建设课程设计
  • 网站 建设 标准方案网站制作平台公司
  • 领域网站建设百度电话怎么转人工
  • 网站漂浮特效网站做虚假广告
  • SEO网站公司淘宝网站的订单管理怎么做
  • 太湖度假区建设局网站竞价网站推广
  • 建设网站怎么賺钱旭泽建站
  • 安庆高端网站建设公司php做直播网站
  • 网站建设中最基本的决策之一是吉林省住房城乡建设厅网站首页
  • 如何创建div做网站乌海seo公司
  • 建站神器医疗网站建设公司
  • 什么是自建站优质龙岗网站建设
  • 青岛网站关键词手机定制app
  • 吉安网站建设最近消息报道
  • 用虚拟主机做网站北京爱空间装修公司
  • 广西建设工程质量监督网站注册完域名之后怎么找到网站
  • 上海虹桥站wordpress在这个站点注册
  • 自己有网站怎么做点卡114啦网址导航建站系统
  • 网页设计与网站建设课程pc网站转换手机网站代码
  • 站长素材音效10万以下纯电动汽车排名
  • 中国市政建设局网站新平台推广赚钱
  • 协会建设网站的目的前端小说