这些解决方案各有优劣,从架构的角度,大致是以下几种模式:
跨平台方案的几种类型
1. 桥接(Bridge)
桥接要解决的核心问题是两种语言(JS 和原生语言)之间的通信,或者说 JS thread 和 native thread 之间的通信。 native layer 的能力被 bridge layer 封装起来,然后提供给 JS layer 调用,反过来,JS layer 的功能也可以借由 bridge layer 供 Native layer 调用。
这个模型很像客户端与服务器之间的通信,客户端和服务器约定好服务接口(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 的成本
进程间通信可以使用很多方式来进行消息的传递,比如大家熟悉的管道(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 性能高的同时,又不依赖平台侧的控件。
现有跨平台方案中的问题
目前所有这些方案的着眼点还是局限在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 模式,可以构想出来这么一套前端代码的前后端分离的模型:
这个模型相对于传统的 UI 跨平台方案,其最大不同是:让所有的相关方处理自己最擅长的事情,而不要强行适配。和平台相关的代码,比如 UI,平台设备的访问等,用更擅长做这件事情的平台原生语言实现(或者 flutter),而平台无关的业务逻辑代码,算法,网络层代码,使用 Rust 来实现。这样,Rust backend 不用去花大量的精力去包裹平台的东西,而只需干好一个 backend 需要干好的事情。
通信方式
之前的 UI 方案,采用的都是 JSON 或者类 JSON 的序列化方案,JSON 是效率非常低下,且类型安全度比较低的一种序列化方案,在这样的场景下,我们还有更多更好效率更高类型更安全的方案,比如 protobuf,flatbuffers 等。
反序列化 | 序列化 |
---|---|
![]() | ![]() |
以 Rust 和 Kotlin 之间做通信为例,使用 JSON 以及 Protobuf 的通信流程分别如下:
JSON | Protobuf |
---|---|
![]() | ![]() |
Rust 和 Kotlin 分别将定义好的 protos 编译成平台代码,然后可以在两端自由地传递 protobuf 的数据。
示例
比如要展示电影网站 Tubi 的首页,假设我们基于 clean architecture 的 MVP 结构实现此逻辑
- 后端提供 API 获取电影列表
GET /api/v1/get_movies
- 建立一个
TubiRepository
处理网络层的请求 - 请求的响应被反序列化成 Category / Movie models,然后以 Entity 的形式交给 Use cases
- 最后presentation layer 将结果被渲染到屏幕
这里,尝试对 Model层 用Rust实现,如下:
- 暴露给 native 层的方法是:
getMovies()
- getMovies() 内部将参数序列化成 protobuf 传递给一个 Rust 函数
dispatcher
- dispatcher 反序列化请求后得知是一个 RequestGetMovies,随后被 dispatch 给
get_movies()
- get_movies()从本地 cache 里读取数据,读不到的话通过 reqwest 从远程 API 获取数据并缓存
从 native 开发者的角度,她就调用了一个 getMovies()
后返回了序列化好的 Movie,Category等数据结构,其它的细节不需要理会。
再举个例子,用户在观看视频的时候,客户端会定期向服务器汇报当前观看的位置
- API:
PUT /api/v1/update_history
- 在 native 层暴露出一个
updateHistory()
的方法 - dispatcher 将其 dispatch 给 Rust 函数
update_history()
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
![](https://i-blog.csdnimg.cn/blog_migrate/7275d9499084088e5a6c7ff0429b3666.jpeg)
最后
你要问前端开发难不难,我就得说计算机领域里常说的一句话,这句话就是『难的不会,会的不难』,对于不熟悉某领域技术的人来说,因为不了解所以产生神秘感,神秘感就会让人感觉很难,也就是『难的不会』;当学会这项技术之后,知道什么什么技术能做到什么做不到,只是做起来花多少时间的问题而已,没啥难的,所以就是『会的不难』。
我特地针对初学者整理一套前端学习资料,免费分享给大家,戳这里即可免费领取
难的,所以就是『会的不难』。
我特地针对初学者整理一套前端学习资料,免费分享给大家,戳这里即可免费领取
[外链图片转存中…(img-glLUYQf0-1712203758388)]