Rust跨平台探索:前端中的后端(1),web后台开发

本文探讨了跨平台开发中的几种常见模式,如桥接(如ReactNative和Cordova)、进程间通信(如Electron)和Canvas绘制(如Flutter),并指出业务逻辑层跨平台的挑战,提出Rust作为可能的解决方案。作者还强调了前端中的后端分离和使用更高效的数据序列化技术的重要性。
摘要由CSDN通过智能技术生成

这些解决方案各有优劣,从架构的角度,大致是以下几种模式:

跨平台方案的几种类型

1. 桥接(Bridge)

桥接要解决的核心问题是两种语言(JS 和原生语言)之间的通信,或者说 JS thread 和 native thread 之间的通信。 native layer 的能力被 bridge layer 封装起来,然后提供给 JS layer 调用,反过来,JS layer 的功能也可以借由 bridge layer 供 Native layer 调用。

image.png

这个模型很像客户端与服务器之间的通信,客户端和服务器约定好服务接口(REST API)后,通过 JSON 交换数据。React Native 借鉴了这种模式,通过 JS bridge 来回传递 JSON。

桥接的代表是:Cordova / React native。两者的区别是在 Cordova 的 UI 层基于 WebView 渲染,所以只需要通过桥接调用 Native 基础服务;而 RN 的 UI 基于平台渲染,因此在 UI 层也做大量了桥接。由于 JS bridge 层依靠 JSON 通信,当大量数据在两端传输时(复杂的动画,大列表的快速滑动),JSON 的性能瓶颈会造成UI卡顿。

2. 进程间通信(IPC)

在桌面系统上,应用程序有更多的灵活性,可以通过使用多进程来组织自己的应用程序。我们同样可以通过进程间通信来解决 JS 和 原生语言之间的调用问题,其代表方案是:Electron。

Electron 使用 IPC 某种程度上说也是迫不得已,因为其依赖的 chromium rengier engine 就是为每一个窗口开启一个进程。对于 chrome 来说,这是一个合理的设计,一个 tab 内部的 crash 不会导致整个 chrome crash。 然而对依赖于 Electron 的桌面应用来说这样设计没有必要,反而增加了 IPC 的成本

image.png

进程间通信可以使用很多方式来进行消息的传递,比如大家熟悉的管道(pipe)。然而,Eletron 使用了 web worker API postMessage 相同的 structured clone algorithm 来做 IPC 数据的序列化和反序列化。这个方法效率和 JSON 差不太多,在传输大量数据时同样会有性能问题,所以 Electron 推荐使用 CSS animation,而非常不建议做 JS anination。

3. 基于 Canvas 绘制

Canvas绘制是实现UI跨平台的主流思路:

  • 平台渲染: 用 JS 来调用原生 UI, 这是 React Native 采用的方式。优点是大部分时候性能足够好;缺点是 JS bridge 需要适配所有支持的平台,当平台侧UI控件想要在RN中使用,需要开发者花费额外精力去适配。
  • 统一渲染: 用其他技术来模拟原生 UI。这是 Cordova / Electron 采用的方式。优点是代码简单,UI 直接在第三方渲染器(webview)中渲染出来;缺点是 UI 性能受 JS 单线程及 webview 本身渲染性能的影响,在复杂交互时往往表现不佳。

当大多数选择统一渲染方案的技术栈只是把目光停留在了webview ,人们忽略了其实所有的 UI 渲染,最终都是在 canvas 上一个像素一个像素填充出来的。如果做一套系统,略过 dom/css/js 复杂的渲染逻辑,直接定制好各种各样的控件,将其绘制到 canvas 上,是不是可以鱼与熊掌兼得?

做到这点的要数 flutter 了。它使用 chrome 底层的图形渲染引擎 skia,从底向上设计出来一套可以高效工作的控件库,比 webview 性能高的同时,又不依赖平台侧的控件。

image.png

现有跨平台方案中的问题

目前所有这些方案的着眼点还是局限在UI层的跨平台,那么业务逻辑代码怎么办?用JS这样的 UI 层的语言撰写难以保证运行时效率,最终还是要诉诸于 native 语言实现,原本一种语言统一天下的初衷,最终发现要学习三种语言,iOS、android、JS/dart 各来一套(flutter可能做得稍微强一点儿,但是依然需要借助 channel 调用平台侧的服务)。

“相比UI跨平台,如何在业务逻辑层跨平台是一个容易被忽略但更值得被关注的问题。”

那么为什么逻辑层跨平台技术进展如此缓慢呢?一个主要原因是没有一个合适的语言工具,很难找到一门语言能够同时覆盖这么多平台的原生语言的优势。

在 Rust 成熟以前,C/C++ 几乎是跨端做业务逻辑的唯一的选择。用 C/C++ 实现一次,然后在各个端上用静态链接的方式编译到 app 中。当然这免不了要做很薄的一层接口:每个平台原生语言到 C/C++ 的桥接。

但是 C/C++ 的代码(相对于 java/kotlin/swift来说)的撰写难度较高,跨平台编译链接有很多坑要踩,最终会遮掩所谓「一次撰写,到处链接」的好处。

如今有了Rust, Rust 有不输于任何一门现代语言的依赖管理和生态,有非常完备的跨平台编译系统和跨语言FFI支持,而 Rust 本身的不依赖运行时的内存安全和并发安全性,还有几乎最高质量的 webassembly 支持,使其成为 C/C++ 跨平台的完美替代品。除了 rust 本身的跨平台工具链之外,Rust 生态里还有专门为简化与 iOS 原生语言互操作的工具 cargo lipo(封装 C FFI),以及为与 java 互操作的 jni,甚至还有专门针对 Android 的 android-ndk-rs。

接下来,我们需要的就是一套组织各个平台原生语言和 Rust 互操作的思路,来解决通用性的问题。

前端中的后端

所谓前端中的后端,就是在前后端分离的基础上,进一步把前端中偏 UI 的业务逻辑和偏数据处理的业务逻辑分开。而掌管数据处理的这部分功能,我们管它叫前端中的后端。

基本架构

无论是前端架构中被广泛使用的 MVC 还是 MVVC 模式,其第一个 M,Model(包含数据,状态,以及业务逻辑),就是我们要分离出来统一处理的「后端」。借鉴之前提到的 bridge 模式,可以构想出来这么一套前端代码的前后端分离的模型:

image.png

这个模型相对于传统的 UI 跨平台方案,其最大不同是:让所有的相关方处理自己最擅长的事情,而不要强行适配。和平台相关的代码,比如 UI,平台设备的访问等,用更擅长做这件事情的平台原生语言实现(或者 flutter),而平台无关的业务逻辑代码,算法,网络层代码,使用 Rust 来实现。这样,Rust backend 不用去花大量的精力去包裹平台的东西,而只需干好一个 backend 需要干好的事情。

通信方式

之前的 UI 方案,采用的都是 JSON 或者类 JSON 的序列化方案,JSON 是效率非常低下,且类型安全度比较低的一种序列化方案,在这样的场景下,我们还有更多更好效率更高类型更安全的方案,比如 protobuf,flatbuffers 等。

反序列化序列化
image.pngimage.png

以 Rust 和 Kotlin 之间做通信为例,使用 JSON 以及 Protobuf 的通信流程分别如下:

JSONProtobuf
image.pngimage.png

Rust 和 Kotlin 分别将定义好的 protos 编译成平台代码,然后可以在两端自由地传递 protobuf 的数据。

示例

比如要展示电影网站 Tubi 的首页,假设我们基于 clean architecture 的 MVP 结构实现此逻辑

  • 后端提供 API 获取电影列表 GET /api/v1/get_movies
  • 建立一个 TubiRepository 处理网络层的请求
  • 请求的响应被反序列化成 Category / Movie models,然后以 Entity 的形式交给 Use cases
  • 最后presentation layer 将结果被渲染到屏幕

image.png

这里,尝试对 Model层 用Rust实现,如下:

  1. 暴露给 native 层的方法是:getMovies()
  2. getMovies() 内部将参数序列化成 protobuf 传递给一个 Rust 函数 dispatcher
  3. dispatcher 反序列化请求后得知是一个 RequestGetMovies,随后被 dispatch 给 get_movies()
  4. get_movies()从本地 cache 里读取数据,读不到的话通过 reqwest 从远程 API 获取数据并缓存

image.png

从 native 开发者的角度,她就调用了一个 getMovies() 后返回了序列化好的 Movie,Category等数据结构,其它的细节不需要理会。

再举个例子,用户在观看视频的时候,客户端会定期向服务器汇报当前观看的位置

  1. API: PUT /api/v1/update_history
  2. 在 native 层暴露出一个 updateHistory() 的方法
  3. dispatcher 将其 dispatch 给 Rust 函数 update_history()

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

完整版面试题资料免费分享,只需你点赞支持,动动手指点击此处就可免费领取了

前端实习面试的套路


回顾项目

往往在面试时,面试官根据你简历中的项目由点及面地展开问答,所以请对你做过的最好的项目进行回顾和反思。回顾你做过的工作和项目中最复杂的部分,反思你是如何完成这个最复杂的部分的。

面试官会重点问你最复杂的部分的实现方法和如何优化。重点要思考如何优化,即使你项目中没有对那部分进行优化,你也应该预先思考有什么优化的方案。如果这部分答好了,会给面试官留下很不错的印象。

重点在于基础知识

这里指的基础知识包括:前端基础知识和学科基础知识。

前端基础知识:html/css/js 的核心知识,其中 js 的核心知识尤为重要。比如执行上下文、变量对象/活动对象(VO/AO)、作用域链、this 指向、原型链等。

学科基础知识:数据结构、计算机网络、算法等知识。你可能会想前端不需要算法,那你可能就错了,在大公司面试,面试官同样会看重学生这些学科基础知识。
你可能发现了我没有提到React/Vue这些框架的知识,这里得说一说,大公司不会过度的关注这方面框架的知识,他们往往更加考察学生的基础。
这里我的建议是,如果你至少使用或掌握其中一门框架,那是最好的,可以去刷刷相关框架的面试题,这样在面试过程中即使被问到了,也可以回答个 7788。如果你没有使用过框架,那也不需要太担心,把重点放在基础知识和学科基础知识之上,有其余精力的话可以去看看主流框架的核心思想。

识,这里得说一说,大公司不会过度的关注这方面框架的知识,他们往往更加考察学生的基础。
这里我的建议是,如果你至少使用或掌握其中一门框架,那是最好的,可以去刷刷相关框架的面试题,这样在面试过程中即使被问到了,也可以回答个 7788。如果你没有使用过框架,那也不需要太担心,把重点放在基础知识和学科基础知识之上,有其余精力的话可以去看看主流框架的核心思想。

  • 15
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值