Flutter Web 的发展历程:Dart、Flutter 与 WasmGC

Flutter Web 应该是 Flutter 开发者里最不“受宠”的平台了,但是其实 Flutter 和 Dart 团队对于 Web 的投入一直没有减少,这也和 Flutter 还有 Dart 的"出生"有关系,今天就借着 Dart 团队的 Ömer Ağacan 和 Martin Kustermann 在油管的访谈视频来聊一聊 Flutter Web 这一路过来的变化。

其实在以前我们聊过很多次,Flutter 早期的项目代号是 “Sky” ,诞生于 Google 内部的 Chrome 团队,早期定位其实是一个「前端项目」,本身是为了探索更优秀的 Web 渲染技术而存在,所以起初 Flutter 的创始人和整个团队几乎都是来自 Web :

Dart 最初的宏大愿景是在 Chrome 的 V8 引擎中内置一个专门的 Dart 虚拟机(VM) ,目的是为 Web 提供一个比 JavaScript 更结构化、性能更强的替代方案。

当然,众所周知这个计划最终凉了,而后 Dart 团队将战略重心转向了 dart2js 编译器,也就是将 Dart 代码转译为 JavaScript,这也是一开始的 Flutter Web 打下来基础。

所以 Flutter 选择 Dart 其中一个原因不难理解,大家都是同一个团队内的,并且 Dart 没什么其他选择,它也可以一心一意成为 Flutter 的形状

当然,另外一个原因则是 Flutter 当时希望有一种语言同时支持 JIT 和 AOT,并且支持 Hotload ,而 Dart 恰好具备这两种编译模式的基础能力。

所以,对于 Dart 来说,它的演进路径其实可以说是“一路坎坷”,从 “Dart VM in V8” 的失败,再到 dart2js 的“苟活”,再到后面 Flutter Web 的落地,以及之后的 WasmGC 提案,再到现在的 dart2wasm ,其实 Dart 一直心系 Web 平台,因为这是它曾经目标的延续。

而对于 Flutter 来说, dart2js 将 Flutter 转译为 JavaScript 的实现,让 Flutter 在 Web 平台变得“不那么一致”,特别是在处理复杂动画和大量 UI 元素时会遇到性能瓶颈,此时的 Web 平台的特殊性也成了 Flutter 的技术债务。

所以 WebAssembly (Wasm) 平台最终成了 Flutter Web 的新目标,它能够让 Flutter 在 Web 平台和其他平台上渲染效果对齐,并且还能提供不错的性能,只是 Wasm 的初始版本(CanvasKit)缺少垃圾回收(GC)机制,不适合像 Dart 这样的托管语言:

Wasm MVP 只提供了一个单一的、连续的内存块,Wasm 模块必须手动管理这块内存,包括对象的分配和释放;并且没有 GC 支持,也就是其他语言必须将它们自己的整个垃圾回收器实现打包进 Wasm 模块,这不仅降低了效率,还极大地增加了代码体积。

最经典的问题是,这会导致在一个进程中同时运行两个 GC 的尴尬局面:一个是打包在 Wasm 模块内的 GC,另一个是浏览器用于管理 JavaScript 对象的 GC

所以早期 CanvasKit 在 Flutter Web 里并没有什么优势,大家还是更愿意基于 dart2js ,这也导致了 Flutter Web 一直处于两种模式的尴尬局面。

因此 ,Dart 和 Flutter 团队开始加入 WasmGC 的推动与落地工作,其实这是一项吃力不讨好的过程,Google 从一开始就深度参与了标准的制定,好处就是确保了这个标准能尽可能满足 Dart 的需求。

当然,最终受惠的还有 Kotlin/Wasm ,JetBrains 也率先基于 WasmGC 开发了全新的 Kotlin/Wasm 编译器验证了相对应的可行性,也是早期的积极实践者之一。

WasmGC 从根本上将 WebAssembly 从一个“Web 上的更好的 C++ 平台”转变为一个“通用的高级语言虚拟机”,而 WasmGC 提案也为 WebAssembly 引入了一系列新的功能:

  • WasmGC 引入了新的堆类型,用于创建结构化数据(struct)和数组(array),让虚拟机能够了解它们的内存布局,从而高效地访问字段,减少复杂的地址计算
  • WasmGC 为托管对象定义了一个类型系统,包含了子类型化(sub)的概念,也就是 Wasm 代码能够表示源语言中的类继承关系,编译器可以将语言的类型层次结构直接映射到 Wasm 的类型系统上
  • WasmGC 引入了一套新指令,例如用于创建实例的 struct.newarray.new,用于字段访问的 struct.getstruct.set,以及用于类型转换和检查的指令,如 ref.cast(类型转换)和 br_on_cast(带类型检查的分支)

编译器不再是将语言的对象模型编译到线性内存中,而是将语言的对象模型映射到 WasmGC 的对象模型上 ,而 WasmGC 相较于传统的将 GC 捆绑到 Wasm 模块中的方法,主要好处在于:

  • 代码体积的急剧减小,由于不再需要捆绑内存管理代码(无论是 malloc 还是一个完整的 GC),最终的 Wasm 二进制文件可以小得多
  • WasmGC 实现了 Wasm 和 JavaScript 之间真正细粒度的对象互操作,一个 WasmGC 对象可以持有对一个 JavaScript 对象的引用,反之也是,这让宿主的 GC 能够正确地追踪和回收跨越这两个环境的循环引用
  • 由于虚拟机了解 Wasm 堆上的对象结构,浏览器开发者工具(如堆分析器)能够检查 Wasm 内存,并显示有意义的对象类型和字段信息

所以,基于 WasmGC 推进的顺路,Flutter 官方在 Flutter 3.10 终于对于 Web 的未来有了明确的定位:

“Flutter Web 是第一个围绕 CanvasKit 和 WebAssembly 等新兴 Web 技术进行架构设计的框架。”

Flutter 团队表示,Flutter Web 的定位不是设计为通用 Web 的框架,类似的 Web 框架现在有很多,比如 Angular 和 React 等在这个领域表现就很出色,而 Flutter 应该是围绕 CanvasKit 和 WebAssembly 等新技术进行架构设计的框架。

而对于 Dart,也从 Dart 3 开始,对于 Web 的支持将逐步演进为 WebAssembly 的 Dart native 的定位

什么是 WebAssembly 的 Dart native 现在应该很好理解了吧?一直以来 Flutter 对于 WebAssembly 的支持都是:使用 Wasm 来处理CanvasKit 的 runtime,而 Dart 代码会被编译为 JS,而这对于 Dart 团队来时,其实是一个「妥协」的过渡期,而基于 WasmGC, Dart 已经开始支持直接编译为原生的 Wasm 代码

dart2js 切换到 dart2wasm 带来了显著的性能飞跃,例如 WasmGC 编译的应用在帧渲染速度上平均提升了 2 倍,而在衡量卡顿情况的第 99 百分位帧上,性能提升高达 3 倍 ,另外 wasm 构建的 Flutter Web 应用还支持了使用多个线程场景,而 HTML renderer 也在 3.29 版本正式移除

skwasm 支持通过一个专用的 Web Worker 在独立线程上进行渲染,可以将部分渲染工作负载分流,利用多核 CPU 来减少卡顿并提高响应性,前提是服务器必须配置特定的 COOP 和 COEP HTTP 标头,从而满足 SharedArrayBuffer 的安全要求 。

当然,WasmGC 目前还是存在浏览器兼容性问题,比如:

  • Chromium (Chrome, Edge): 从 119 版本稳定支持 WasmGC
  • Firefox: 尽管从 120 版本开始支持 WasmGC,但存在一些特定错误,某些情况可以会导致 Flutter 的 skwasm 渲染器无法正常工作
  • Safari/WebKit: 同样已经支持 WasmGC,但也存在阻碍 Flutter 渲染的错误,特别是 iOS 上的 WebKit 兼容问题

目前 WebKit 已经默认支持了 WasmGC ,但是历史版本依然存在需要兼容的场景:

而回归到 Flutter Web 上,就是 canvaskitskwasm 有什么区别?简单说:

  • canvaskit 使用 dart2js,兼容性更广
  • skwasm 使用 dart2wasm ,性能更好体积更小,但是依赖 WasmGC 环境

所以,也许 Flutter Web 在开发者领域并不是很受宠,但是 Flutter 和 Dart 对它的投入并不少,因为 Wasm 的潜力已经远远超出了浏览器的范畴 ,例如 WASI(WebAssembly System Interface)就是未来的重要趋势之一,作为新兴的标准,它的目的是为 Wasm 模块提供一种安全、可移植的方式来与系统资源(如文件系统)进行交互 。

WASI 的目标是定义一套标准的 API,让 Wasm 代码可以“一次编译,在任何(支持 WASI 的)运行时上运行”,无论是服务器、边缘设备还是桌面应用。

例如:

  • WASI 可以让 WebAssembly 成为 Node.js 和 Python 等传统服务器运行时的高性能替代品
  • 借助 WASI,Wasm 模块将能够和传感器、本地文件系统交互来处理边缘设备上的数据,从而实现边缘的实时决策
  • WASI 的系统级功能能让 WebAssembly 在传统容器领域成为轻量级替代品

dart2wasm 编译器目前是主要针对浏览器中的 JS 环境,但未来它也许可以被扩展以支持非 JS 的、符合 WASI 标准的运行时,例如 Wasmtime 或 Wasmer ,从而支持更多场景,这也是为什么 Flutter 和 Dart 对于 Wasm 持续投资的原因之一。

这也是访谈里 Ağacan 和 Kustermann 未来愿景:在一个通用的、高性能的、可移植的运行时的驱动下,原生应用和 Web 应用之间的界限会更加模糊,尽管挑战依然存在,但其发展轨迹已经为一类全新的 Web 体验设定了方向。

而回归的目前的 Flutter Web 和当前推进的情况,未来大概会有:

  • Flutter Web Hotload 的稳定版发布
  • 基于 Flutter Web 的 IDE 内 Widget Preview 稳定版
  • 基于语义树实现 SEO 优化,例如 #145954 就提到过,通过将无障碍的 Semantics Tree 翻译成 HTML 结构的管线,让 Web 可以满足搜索引擎爬虫读取的需求

虽然 Flutter Web 现在还不够好用,不够通用,但是它也确确实实撑起了 Flutter 在 Web 平台的能力,对比起刚刚才合并到 master 的桌面端多窗口的情况,其实 Web 的投入在每个版本都有目共睹,未来 Flutter Web 应该也不会往通用领域发展,但是在 WebAssembly 领域,Flutter 和 Dart 应该还是可以有一席之地。

参考链接

  • https://www.youtube.com/watch?v=vgOABOvtBT8

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/914768.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/914768.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c#方法关键字,ref、out、int

在 C# 中,ref、out 和 in 是用于方法参数传递的关键字,它们控制参数如何在方法和调用者之间传递数据。以下是对这三个关键字的详细分析:1. ref 关键字(引用传递)作用允许方法修改调用者的变量:通过引用传递…

设计模式—初识设计模式

1.设计模式经典面试题分析几个常见的设计模式对应的面试题。1.1原型设计模式1.使用UML类图画出原型模式核心角色(意思就是使用会考察使用UML画出设计模式中关键角色和关系图等)2.原型设计模式的深拷贝和浅拷贝是什么,写出深拷贝的两种方式的源…

深度学习-参数初始化、损失函数

A、参数初始化参数初始化对模型的训练速度、收敛性以及最终的性能产生重要影响。它可以尽量避免梯度消失和梯度爆炸的情况。一、固定值初始化在神经网络训练开始时,将权重或偏置初始化为常数。但这种方法在实际操作中并不常见。1.1全零初始化将所有的权重参数初始化…

格密码--Ring-SIS和Ring-LWE

1. 多项式环&#xff08;Polynomial Rings&#xff09; 设 f∈Z[x]f \in \mathbb{Z}[x]f∈Z[x] 是首一多项式&#xff08;最高次项系数为1&#xff09; 则环 RZ[x]/(f)R \mathbb{Z}[x]/(f)RZ[x]/(f) 元素为&#xff1a;所有次数 <deg⁡(f)< \deg(f)<deg(f) 的多项式…

前端工作需要和哪些人打交道?

前端工作中需要协作的角色及协作要点 前端工作中需要协作的角色及协作要点 前端开发处于产品实现的 “中间环节”,既要将设计方案转化为可交互的界面,又要与后端对接数据,还需配合团队推进项目进度。日常工作中,需要频繁对接的角色包括以下几类,每类协作都有其核心目标和…

万字长文解析 OneCode3.0 AI创新设计

一、研究概述与背景 1.1 研究背景与意义 在 AI 技术重塑软件开发的浪潮中&#xff0c;低代码平台正经历从 “可视化编程” 到 “意图驱动开发” 的根本性转变。这种变革不仅提升了开发效率&#xff0c;更重新定义了人与系统的交互方式。作为国内领先的低代码平台&#xff0c;On…

重学前端006 --- 响应式网页设计 CSS 弹性盒子

文章目录盒模型一、盒模型的基本概念二、两种盒模型的对比 举例三、总结Flexbox 弹性盒子布局一、Flexbox 的核心概念​​二、Flexbox 的基本语法​​​​1. 定义 Flex 容器​​​2. Flex 容器的主要属性​​​​3. Flex 项目的主要属性​​​​三、Flexbox 的常见布局示例​​…

rLLM:用于LLM Agent RL后训练的创新框架

rLLM&#xff1a;用于LLM Agent RL后训练的创新框架 本文介绍了rLLM&#xff0c;一个用于语言智能体后训练的可扩展框架。它能让用户轻松构建自定义智能体与环境&#xff0c;通过强化学习进行训练并部署。文中还展示了用其训练的DeepSWE等智能体的出色表现&#xff0c;以及rLL…

rocky8 --Elasticsearch+Logstash+Filebeat+Kibana部署【7.1.1版本】

软件说明&#xff1a; 所有软件包下载地址&#xff1a;Past Releases of Elastic Stack Software | Elastic 打开页面后选择对应的组件及版本即可&#xff01; 所有软件包名称如下&#xff1a; 架构拓扑&#xff1a; 集群模式&#xff1a; 单机模式 架构规划&#xff1a…

【JVM】内存分配与回收原则

在 Java 开发中&#xff0c;自动内存管理是 JVM 的核心能力之一&#xff0c;而内存分配与回收的策略直接影响程序的性能和稳定性。本文将详细解析 JVM 的内存分配机制、对象回收规则以及背后的设计思想&#xff0c;帮助开发者更好地理解 JVM 的 "自动化" 内存管理逻辑…

Qt获取hid设备信息

Qt 中通过 HID&#xff08;Human Interface Device&#xff09;接口获取指定的 USB 设备&#xff0c;并读取其数据。资源文件中包含了 hidapi.h、hidapi.dll 和 hidapi.lib。通过这些文件&#xff0c;您可以在 Qt 项目中实现对 USB 设备的 HID 接口调用。#include <QObject&…

Anaconda Jupyter 使用注意事项

Anaconda Jupyter 使用注意事项 1.将cell转换为markdown。 First, select the cell you want to convertPress Esc to enter command mode (the cell border should turn blue)Press M to convert the cell to Markdown在编辑模式下按下ESC键&#xff0c;使单元块&#xff08;c…

[硬件电路-20]:模拟信号处理运算与数字信号处理运算的相同点与不同点

模拟信号处理运算与数字信号处理运算是信号处理领域的两大核心方法&#xff0c;二者在信号形式、处理机制、性能特点和应用场景上存在显著差异&#xff0c;但也共享一些基础目标与理论支撑。以下从多个维度进行系统对比分析&#xff1a;一、相同点1. 核心目标一致信号变换与分析…

Redis 高频面试题

1. 缓存穿透 1.1 描述 用户想要查询某个数据,在 Redis 中查询不到,即没有缓存命中,这时就会直接访问数据库进行查询。当请求量超出数据库最大承载量时,就会导致数据库崩溃。这种情况一般发生在非正常 URL 访问,目的不是为了获取数据,而是进行恶意攻击。 1.2 现象 1、应…

OWASP Top 10 攻击场景实战

OWASP (开放式Web应用程序安全项目) Top 10 榜单是全球公认的、针对Web应用最关键安全风险的权威指南。它不是一份详尽无遗的清单&#xff0c;而是一份凝聚了安全专家共识的“高危预警”。本文将不止于罗列这些风险&#xff0c;而是深入每个风险的核心&#xff0c;通过生动的比…

Three.js 实战:使用 PBR 贴图打造真实地面材质

在 Three.js 中&#xff0c;我们可以通过 MeshStandardMaterial 材质配合多张贴图来实现真实的地面效果。这种方式模拟了物理世界中光照与表面材质的复杂交互&#xff0c;常用于构建高质量场景&#xff0c;如数字孪生、建筑可视化、游戏等。 本文将以一个完整示例为基础&#x…

Java基础的总结问题(第一篇)

JDK和JRE的区别&#xff1f;JRE是Java运行环境&#xff08;Java Runtime Environment&#xff09;&#xff0c;包含了JVM和Java核心类库JDK是Java开发工具包&#xff08;Java Developers Kit&#xff09;,包含了JRE和Java常见的开发工具与equals的区别&#xff1f;可以用来比较…

[智能算法]MOEA/D算法的Python实现

一、初始化不同于NSGA-II&#xff0c;MOEA/D在进行迭代之前需要先进行初始化&#xff0c;初始化的主要内容是计算个体向量权重之间的欧氏距离&#xff0c;并得出其邻域集合。# 计算T个邻居 def cpt_W_Bi_T(moead):# 设置的邻居个数错误(自己不能是自己的邻居)if moead.T_size &…

Java设计模式之-组合模式

什么是组合模式&#xff1f; 组合模式允许你将对象组合成树形结构来表示"部分-整体"的层次结构。它让客户端能够以统一的方式处理单个对象和对象组合。 简单来说&#xff0c;就像公司的组织结构&#xff1a; 公司有部门部门有小组小组有员工但无论是对公司、部门还是…

2021-10-29 C++与反转数的和

缘由输入一个三位数 与它倒过来的数相加&#xff0c;输出和-编程语言-CSDN问答 直接写 int n0,nn0,nnn0; cin>>n;nnn; while(nn)nnn*10,nnnnn%10,nn/10; cout<<nnnn<<endl; 缘由https://ask.csdn.net/questions/7552128 int 反转数(int n) { int nn 0…