专栏名称: 美团技术团队
10000+工程师,如何支撑中国领先的生活服务电子商务平台?数亿消费者、数百万商户、2000多个行业、几千亿交易额背后是哪些技术在支撑?这里是美团、大众点评、美团外卖、美团配送、美团优选等技术团队的对外窗口。
目录
相关文章推荐
字节跳动技术团队  ·  远程访问代理+内网穿透:火山引擎边缘网关助力 ... ·  12 小时前  
字节跳动技术团队  ·  稀土掘金 x Trae ... ·  12 小时前  
51好读  ›  专栏  ›  美团技术团队

大前端:如何突破动态化容器的天花板?

美团技术团队  · 公众号  · 架构  · 2024-10-17 19:58

正文

请到「今天看啥」查看全文


  • 第二层,其作用就像它的名字一样,也就是运行时支持,为运行UI框架提供支持,在这里会有解释器或者是标准库之类的东西。
  • 第三层,会对不同平台去做一层不同的抽象,比如像RN会对视图操作之类的统一为相同概念和统一接口。
  • 第四层,渲染层,对应着不同分类选择的各自的渲染的方式。
  • 那么下面,我们就会基于上图对现有容器这个分类和结构为认知基础,结合之前影响容器性能表现最大的因素在于逻辑解释器执行效率和逻辑解释器通信效率这个认知,再去考虑实现一个满足性能、安全、动态化的容器方案该怎么做。

    3 Recce的选型与搭建

    所以如何选择UI框架、运行时支持、平台抽象层、渲染层 来实现一个高性能、安全的动态化容器呢。首先把渲染层放到最后,因为渲染层作为最底层并不影响上层选型。然后我们首先讨论运行时支持怎么选,准确的说是解释器和编程语言怎么选,因为编程语言会影响上层UI框架,而解释器也影响到平台抽象层中的通信部分,所以接下来的讨论顺序是: 解释器&编程语言、UI框架、渲染层以及整体架构 这四部分。

    | 3.1 解释器&编程语言的选择

    解释器以Wasm为主, JavaScript为辅

    前文也提到,我们期望能获得一个既能满足性能,又安全,同时还可以动态化这样的一个方案。既然必须动态化,就必须有逻辑解释器 [1] ,问题就变成了怎样选一个性能好且安全的解释器,并且成本在可接受范围。现成的解释器还是不少的,前端范畴有V8、JavaScriptCore、QuickJS等JavaScript解释器,有符合WebAssembly( 后简称Wasm ) 规范的 Wasmer 、WasmEdge [2] ;大家日常工作中会接触到的Ruby、Python;还有游戏行业用的比较多的Lua、C# [3]

    首先可以排除掉Ruby和Python这两个语言和解释器,无论是性能还是生态都不如JavaScript。Lua和C#也可以排除,主要是游戏生态和前端差距太远,晚饭想吃炸鸡,中午才开始孵蛋显然就来不及了。在JavaScript解释器和Wasm解释器两个大范围里,Wasm解释器在性能和安全上较JavaScript解释器有决定性优势,生态上较JavaScript略差,但都在W3C标准范围内,一样可以运行在H5和小程序里,“晚饭想吃炸鸡,中午开始杀鸡还是来得及的”。

    所以在解释器的选型上,就确定了Wasm解释器为主,JavaScript为辅的基本策略。而Wasm解释器具体选择是Wasm3,原因有两方面:第一,这是在不支持JIT [4] 下最快的Wasm解释器;第二,对包大小占用非常少。

    编程语言选择

    在确定了Wasm解释器之后,编程语言的选择就变成了,在支持Wasm的语言里选择性能、安全和成本最优的。理论上可以编译成WebAssembly执行的语言非常之多,但真正成熟到可以上生产环境的只有C、C++、Rust、Go这四种 [5] 。首先可以先排除掉C,虽然性能好但是不支持高级抽象只适合用在嵌入式等极端场景,不适合用来前端写业务。然后可以排除C++,性能表现上C++和Rust不相上下都好过Go,但是错误管理和内存安全上输Rust一筹,并且C++在前端业务层也是生态基本为零,不像Rust在前端生态发展迅猛。最后可以排除Go,在性能表现上、类型系统设计、错误管理、还有前端生态上都输Rust一筹。

    综上所述,在运行时我们就选择了Rust和Wasm3,JavaScript和QuickJS后面再进行介绍。

    | 3.2 UI 框架

    用JavaScript/QuickJS的部分可以复用Vue或者React,这些先不提。用Rust则必须要为运行时的上层设计一套UI框架,确定应该怎么样编写页面。这项工作的挑战在于,它并不像JavaScript生态,有多年的积累可供参考或复用,比如经典的React和Vue。当然好处在于也没有历史包袱,所以必须要结合Rust语言的特点才能更好地完成这个任务。

    UI框架大抵需要做到三点:(1)提供声明式DSL方便前端研发描述界面;(2)提供组件封装和状态管理能力完成业务逻辑和用户交互的衔接;(3)性能卓越。其中(1)和(2)在JavaScript生态中已经都有实现,(3)则未必,否则也不会有几十种Web UI框架并存这种局面。这个问题难在如何用Rust这门强类型纯静态语言去实现JavaScript弱类型动态语言实现的功能,并且要维持Rust零开销抽象的优势。

    为了解决这个问题,我们参考了GitHub上开源的各种框架。一方面参考了Dioxus的DSL设计和UI封装,另一方面也保持了 Rust-Dominator观察者模式订阅变更的更新效率,我们将这两个优点合并到一起,就得到了Recce UI,就其特点,没有 Diff,也没有VDOM,跟SolidJS一样实现真正的订阅,我们也尽可能地去保证可以高效地构建UI。下图中的表格对应的就是一些Web项目下的性能对比,这个也并没有直接对应到具体实践的容器上,因为我们也做了一个类似Native渲染的东西,所以这个表格对我们来说具备很好的参考价值,至少可以看到Dominator的更新效率还是很不错的。

    | 3.3 渲染层

    渲染层的选择则相对简单,如前述归纳实现一个渲染层大致三种方式:复用 WebView、自建渲染绘制器、调用系统 UI 框架。
    1. 复用WebView :如果追求高性能,这条路就不通,复用WebView意味着渲染指令/视图树 要用低效的方式以WebView 的JsCore为跳板再去驱动WebCore做渲染。这和高性能就南辕北辙,还不如纯H5性能表现好。
    2. 自建渲染绘制器 :这条路技术上是行得通的,但目前走不得:第一,从代码量上看Chromium内核有数百万行C++,考虑到跨平台兼容则过千万行代码,这个规模和复杂度是超过美团App本身,即使照着写一遍,没有数十名C++专家投入三五年之功是看不到成效的。第二,当世只有Google和Apple有这个能力做成WebView。FireFox的新浏览器计划半途而废,微软则直接放弃转投Chromium。
    3. 调用系统UI框架 :类似RN的方式,研发成本上是我们能接受的;渲染样式虽然没有WebView的CSS全,但是Flex足够支撑业务需求了,且保持是W3C的严格子集;RN在性能上的问题主要出在通信层上,这个我们可以解决掉;最后也是最重要的是这个选择不是一个单向门,假如我们获得了驾驭blink [6] 能力,那么就可以很低的成本平滑切换到blink上。

    所以渲染层就是复用了React Native的Native部分,我们决定要站在这个“巨人”的肩膀上开始行动。毕竟React Native 已经提供了非常优秀的组件封装,同时它也解决了Android和iOS在渲染层面的差异,因为这些接口基本上都是在系统UI下进行封装的,所以我们有理由相信这些接口本身的性能是良好的。







    请到「今天看啥」查看全文