跨端的另一种思路 | D2分享+文章

简介: 跨端的另一种思路:逻辑跨端的探索。

作者 | 当轩

点击查看视频

大家好,我是来自阿里巴巴集团 ICBU 互动端技术团队的当轩,很荣幸能在第十五届 D2 大会上和大家做一次分享 ,我此次分享的主题是《跨端的另一种思路》。

我在开发端应用的时候,常常怀念 Web 的天然跨平台能力和开发效率。然而在开发 Web 应用时又会苦恼没有端应用那么好的性能和体验。所以就常常在想,有没有一种技术方案,像 Web 一样可以便捷的开发、在所有平台都能运行,同时又有很好的性能和体验。

当时最有名的一句宣传语我相信大家都有印象 -- Write Once, Run EveryWhere ,一次编写,到处运行。

image.png
然而理想很饱满,现实很骨感,不同的跨端方案层出不穷,但是都难以达到我们最终理想中的效果。
image.png
举例来说:

  • Web 作为天然的跨端方案,在研发效率上非常不错,然后性能和体验的优化难度都非常高

  • React-Native 类的方案,性能上要比 Web 好了不少,然后多端一致性和研发效率则较低

  • Flutter 在 App 上的性能和一致性不错,但是在差异比较大的 Web 端性能就非常糟糕了,也无法满足 Web SEO 等诉求

之所以理想和现实存在这种差距,是因为跨端的方案本身在带来收益的同时也意味着在某些方面会增加一定的成本。
image.png
例如我们期望用同一套代码覆盖所有平台的同时,又希望研发的自由度和表达能力不要受到限制,然而这种方案只能使用不同平台表达力的子集。最典型的场景就是小程序的跨端方案,静态转译的小程序跨端方案往往通过限制开发者的表达能力来实现一套代码跨多端。

既然现实中的方案在带来收益的同时同样带来成本,我们就不能一味的追求 Write Once, Run EveryWhere我们的实际场景做出取舍。于是我们就提出另外一种成本更低的思路:逻辑跨端。
image.png
今天以我们 Alibaba.com 的交易场景为例,分为 Android/iOS/M 站/PC 网页几个端。
image.png
几端的 UI 交互并不完全一致,但具有相同的业务逻辑,同时 APP 端对于性能和体验上有更高的要求。我们在效率上最直观的问题在于,一个哪怕非常简单的业务需求的上线,都需要经过多端开发同学的资源协调和相互依赖,消耗在沟通上的成本非常高。

由于 Android/iOS 端对于性能体验的要求高,加上这两端的 UI 和交互基本一致,我们考虑用 Flutter 来作为主要的技术选型。然而在 Native 和 Web 之间,Flutter 并没有成熟的跨端方案,前面我们提到过 Flutter for Web 的性能基本是不可用状态。

通过 JavaScript 容器 + Yoga 做类似于 React-Native 的方案我们也考虑过,然而其带来的建设成本和抽象代价在这种场景下是否合适是存疑的,因为 PC 和 App 的交互完全不同,通过引入 Yoga 类的方案反而会让两端的开发都束手束脚。除此之外,我们也担心 JavaScript 容器的引入在端上带来更高的优化成本。

于是我们就提出了另外一种思路:有没有可能仅针对业务逻辑做跨端共享,这样我们不需要对容器侧进行太大的改造,也不用担心引入新的优化成本,同时也能做到跨端共享代码。从而让前端同学去单独 hold 业务侧的需求成为一个可能的方案。

image.png
那么对于这样一种方案我们会有几个问题:

image.png

  • 采取什么语言

  • 如何分离逻辑和 UI

  • 差异逻辑怎么写

第一个问题是采取什么语言,其实 Dart 就是一个现成的选项,因为 Dart 从一开始就是为 Web 设计的语言,甚至在 Flutter 出现前曾经一度在 Chrome 中有默认 VM 实现。虽然后来放弃了在浏览器中的发展,但是 Dart => JavaScript 仍然是一个成熟的技术。

image.png
同时因为我们的前端同学其实对于 Dart 仍然不是那么的熟悉,另外 Dart 的类型系统在很多时候并不能满足动态类型的诉求,以至于到处都是 dynamic。例如说基础的联合类型:string | number 这样的类型都无法直接支持,所以我们也在探索从 TypeScript 转译到 Dart 的方案。

image.png
通过 TypeScript 提供的能力,我们可以直接把一份 TS 的代码从源码解析到 AST,而后通过遍历 AST 生成对应的 Dart 代码。同时其中通过 getTypeChecker.getTypeAtLocation 等 API 获取到 AST 对应的 TS 类型。然后通过把 TS 类型转换成对应的 Dart 类型。对于不支持的类型降级到 dynamic ,把原有的完整类型信息输出到对应的注释里。

image.png
第二个问题是如何有效的分离逻辑和 UI,其实我们都知道如果只是单纯的把纯函数作为一个独立模块给抽离出来并不困难。然而逻辑中必然不仅仅是单纯的输入得到输出的纯模块,还有很多涉及到组件生命周期、渲染、状态变化等副作用(side effect)。如果我们需要在 Flutter 和 Web 间复用逻辑,我们就需要定义一份类似的接口。

我们可以先看看 Flutter 和 Web(我们这里采用的是 React)究竟存在多大差异,这里是 Flutter 和 React 构建组件的一个简单对比。其实我们知道,在代码组织方式上,Flutter 和 React 是非常相似的,事实上他们背后的的状态更新 => 触发 Diff => 重新渲染的逻辑也基本一致。所以说最理想的情况下,我们能直接用同样的逻辑抽象方式共同来书写逻辑,这样可以避免在不同场景下的接口对接方式和心智负担。

image.png
那么,有什么合适的方案可以用于分离逻辑和 UI 呢。其实对于很多前端同学来说,可能都了解 React 16 推出的 React Hooks,我们可以在这里看到相比 React 15 的 Class API 的一个区别。
image.png
看上去好像除了代码量变小外似乎问题不大?但其实如果我们把这个组件拆成两个函数,就能明显看出差别了。

image.png
没错,React Hooks 最大的作用不在于单纯的少写代码,而是让我们可以以非常低的成本把逻辑从 UI 或者其他逻辑中抽离出来,并且进行再组合。也就是说其实 Hooks 就是这么一个现成的逻辑拆分方案,大家也广泛接受其理念和 API。那么,有没有可能让 Hooks 的逻辑在 Flutter 上也能使用呢?

前面我们提到,Flutter 构建组件的方式以及运行原理都和 React 十分的相似,那么我们其实只要理解了 React 中 Hooks 工作的原理,就能在 Flutter 中再实现一遍。Hooks 可以简单理解为 闭包 + 数组(实际上在 React 中是链表)。以 useState 为例,Hooks 和普通函数最大的差异在于其可以在多次 render 调用中保持状态,实际上就是通过在闭包中保留状态,同时通过每次重新 render 时重置计数,从而依赖执行顺序还原出具体的状态。
image.png
那么到了 Flutter 中,我们就可以实现一个 HooksWidget ,在触发渲染时重置计数,同时把当前组件存储到闭包中,从而让 Hooks 能够根据计数找到对应的状态,并且知道应该去触发那个组件的重渲染。
image.png
最后一点就是对于差异化逻辑的书写,Dart 从 x.x 版本就引入了 condtional import 的能力,让我们可以根据不同的环境(Flutter 和 Web 引入不同的包)。于是我们可以在不同的包中书写接口相同,但底层逻辑不同的类,从而实现差异化逻辑。
image.png
同时在 Web 端,我们可以通过 Dart 官方提供的 js 包,轻松的和浏览器中的 JavaScript 原有能力进行交互。于是我们可以通过这样的一层胶水层,让我们在 Flutter 端的逻辑走我们上面写的 Hooks 能力,而在 Web 端则直接调用 React 的 Hooks。

最后我们能实现的一个效果,就是用同一份逻辑代码来表达 Flutter 和 Web 端的业务逻辑,并且作为我们非常熟悉的 Hooks,引入到 UI 上并且直接绑定。

image.png
image.png
image.png
同时借助 SourceMap,我们在 Devtools 里也能进行调试。
image.png
由于我们在渲染上并不强制差异很大的 Web 和 Flutter 保持统一,所以在性能上可以针对不同平台的特性做出优化,比 Flutter for Web 的性能表现更好。

点击查看视频

这个 DEMO 仅代表这个场景下的一个性能对比,并不代表所有场景下的方案性能都如上所示,事实上针对不同的方案我们也可以再采取不同的优化措施去改进。之所以放这个 DEMO,主要是为了解释这种方案在不经过太大投入的情况下,也能达到理想的性能。

image.png
最后我们再做一个大概的总结:

  • Write Once 是一个理想目标,Write Logic Once 在部分场景下能更好的解决我们的问题。

  • 介绍的方案仅适合重逻辑的场景,对于重 UI 表现场景不适用。我们需要根据场景做出对应的选择取舍。

  • 对于写一份逻辑,无论是 Dart 还是 TS,仍然存在一定的抽象泄露问题,对于一些复杂问题的排查仍依赖开发者的经验


🔥第十五届 D2 前端技术论坛 PPT 集合已放出,马上获取

image.png
关注「Alibaba F2E」
回复 「PPT」一键获取大会完整PPT

相关文章
如何用晶体管构建异或门
。XOR ,异或的缩写,它是一种逻辑运算,当高电平输入的数量为奇数时,产生高电平输出;当低电平输入的数量为偶数时,产生低电平输出。这种独特的特性使异或门成为各种应用中的重要组成部分,从简单的二进制算术到复杂的数据加密算法。 在本文中,我们将探讨异或门的内部工作原理,包括其真值表、逻辑符号表示、电路图以及使用晶体管的实际构造。
3338 0
|
8月前
|
人工智能 数据可视化 网络安全
2026年阿里云计算巢部署OpenClaw(Clawdbot)AI助手入门教程
在2026年AI自动化办公与轻量运维需求持续升温的背景下,OpenClaw(前身为Clawdbot、曾用名Moltbot)凭借轻量开源、自然语言驱动、多场景适配的核心优势,成为个人办公提效、中小企业轻量运维、团队协同管理的优选工具。与传统AI助手不同,OpenClaw无需复杂的代码开发能力,仅通过简单对话指令,即可完成文档生成、服务器巡检、网页抓取、插件扩展等自动化任务,真正实现“零基础上手、高效率落地”,其核心价值在于能够将自然语言需求转化为可落地的实操任务,摆脱了普通AI助手“只说不做”的局限。
766 1
|
8月前
|
存储 弹性计算 人工智能
阿里云服务器一年多少钱?ECS和轻量2026 价格表 + 新老用户优惠全汇总
2024年双十一期间,阿里云推出多款优惠云服务器配置。轻量应用服务器2核2G、3M带宽、50GB ESSD云盘,仅需36元/年;云服务器ECS 2核2G、3M带宽、40GB ESSD Entry云盘,99元/年;ECS u1实例2核4G、5M带宽、80GB ESSD Entry盘,199元/年。更多配置详见官网。
1286 9
|
10月前
|
人工智能 运维 机器人
3000万人问AI什么?千问这份榜单让老金看懂了2025年真相
加我进AI讨论学习群,公众号右下角“联系方式”文末有老金的 开源知识库地址·全免费
|
网络协议 物联网 调度
《探秘鸿蒙分布式软总线:开启无感发现与零等待传输新时代》
鸿蒙系统的分布式软总线技术是实现设备互联互通的核心,通过融合Wi-Fi、蓝牙、NFC等通信技术,实现设备无感发现与零等待传输。该技术具备自发现、自组网、高带宽低时延特性,支持多设备协同工作,如智能家居中手机与音箱、空调的无缝连接,办公场景中的文件共享与多屏协同,以及工业互联网中的实时通信。其极简协议、流式传输和智能调度机制大幅提升效率,为用户带来便捷体验,推动智能生态发展。
1109 6
|
安全
一文看懂网络文化经营许可证
一文看懂网络文化经营许可证
1299 3
|
存储 NoSQL 算法
文件上传下载系列——如何实现文件秒传
文件上传下载系列——如何实现文件秒传
|
存储 网络协议 大数据
一文读懂RDMA: Remote Direct Memory Access(远程直接内存访问)
该文档详细介绍了RDMA(远程直接内存访问)技术的基本原理、主要特点及其编程接口。RDMA通过硬件直接在应用程序间搬移数据,绕过操作系统协议栈,显著提升网络通信效率,尤其适用于高性能计算和大数据处理等场景。文档还提供了RDMA编程接口的概述及示例代码,帮助开发者更好地理解和应用这一技术。
|
Web App开发 数据可视化 JavaScript
input标签的type属性汇总
input标签的type属性汇总
989 0

热门文章

最新文章