WebAssembly:A new development paradigm for the web

WebAssembly:A new development paradigm for the web

介绍 WebAssembly 以及它如何为 Web 开发带来新的范式.

WebAssembly 介绍

首先介绍一下 WebAssembly 到底是什么,以及为什么要使用它.

WebAssembly 是一种用于 Web 的低级二进制格式,它是从其他语言编译而来的,以提供最大化的性能,并且旨在增强 JavaScript 不足的地方.

为什么要使用 WebAssembly?

有三个主要优点:

  1. 提供了更可靠和最大化的性能.
  2. 实现了很好的可移植性,因为您可以从其他语言编译,从而使您可以跨部署共享代码.
  3. 为开发人员提供了更大的灵活性,现在开发人员可以使用 JavaScript 以外的语言编写 Web.

也许最重要的是,它现在已经完全在所有主要浏览器中运行,因此您可以可靠地接触所有用户.

他们介绍了四种语言,以展示它们如何进入 Web 以及如何自己入门.

值得注意的是,还有很多其他语言也正在添加对 WebAssembly 的支持.

C++ WebAssembly

WebAssembly 改变 Web 的最早领域之一是通过在 Web 上启用大型应用程序(例如 AutoCAD,Figma 和最近的 Photoshop)来实现的.

这些是性能要求高的应用程序,具有大型代码库,通常是从其他平台移植而来的.

AutoCAD 带来了他们的代码库,该代码库始于 40 多年前,早于第一个浏览器.

现在,该原始代码库的某些部分可以通过简单的链接直接访问.

Figma 从一开始就对 WebAssembly 进行了大胆的赌注,并使用 C++编写了其引擎,以实现最大化的性能.

Photoshop 将其复杂的应用程序带到 Web,实现了易于跨平台共享,包括评论和编辑.

他们还将很快使用 Web ML 进行优化的机器学习操作.

在过去的一年中,我们继续看到更多这些令人难以置信的高级应用程序,利用 Wasm 来到 Web.

Snapchat 希望扩大其受众,同时使用单个代码库来覆盖所有平台.

他们决定 C ++将为他们提供所需的性能和可移植性.

通过利用 WebAssembly,他们可以直接在浏览器中交付整个应用程序,跨所有操作系统.

Snap 还在通过 WebAssembly 投资将其惊人的相机套件带到 Web,您可以在 web.snapchat.com 上自己尝试.

在这里,他们再次重用了跨平台共享的 C++实现.

他们使用 Emscripten,包括其 Embind 绑定系统,以及 OpenGL 到 WebGL 的转换.

他们还使用 TensorFlow.js 进行 ML 推理,Web Workers 进行屏幕外渲染,以及使用 Chrome 分析工具进行性能优化.

WordPress 做了一些非常令人难以置信的事情,实际上设法使 WordPress 服务器环境构建直接在浏览器中运行.

这依赖于将 PHP 解释器本身和 SQLite 编译为 WebAssembly.

有了这个,用户可以直接在浏览器中尝试 WordPress,而无需进行任何设置.

这对于入门,启用交互式教程以及最终支持后端的轻松发布都具有惊人的影响.

通过在 Wasm 上运行,他们现在还可以部署到非浏览器环境,包括 Node.js 或其他 Wasm 服务器环境.

所有这些示例都由 Emscripten 工具链提供支持.

Emscripten 将帮助编译您的 C++代码,但也有助于移植针对 POSIX API 构建的代码,并且甚至将 OpenGL 调用转换为 WebGL.

他们还在实现 WebAssembly 调试方面做出了非常大的改进.

有了此支持,您现在可以在 DevTools 中看到 C++代码,设置断点,逐步执行代码,甚至查看变量的运行时值.

您可能在想,我没有编写 C++或构建大型跨平台应用程序,而是正在进行 Web 开发.

这就是 WebAssembly 库将改变您生活的地方.

这些库包括 OpenCV 用于图像分析,TensorFlow.js 用于 ML,Skia 用于图形,SQLite 用于数据库,FFmpeg 用于视频操作等等.

这些示例都公开了 JavaScript API.

您甚至可能不知道它们在幕后由 WebAssembly 提供支持,它们的性能非常好.

让我们以 Telegram 的令人难以置信的 Web 应用程序为例.

Telegram 是传统的 Web 应用程序,其中大部分功能都是用 JavaScript 构建的.

但是,他们需要一些额外的功能,这些功能可以在 WebAssembly 中找到.

具体而言,他们使用 RLottie 渲染器进行动画贴纸,Opus Recorder 进行语音录制和解码,fastTextWeb 进行语言检测,以及 Webp-hero 进行 Safari 中的 Webp 支持.

实际上,当查看 MPM 时,有 1500 个 WebAssembly 包.

如果您是任何语言的库作者,并且希望将库带到 Web,那么现在就是您的时代.

那么,既然我们已经介绍了 C++,让我们跳到 Swift.

Swift WebAssembly

Swift WebAssembly 已经可以编译一段时间了.

但是,直到工具链和生态系统成熟到可以在生产中使用的程度,这才是真正可用的.

在生产中运行 Swift WebAssembly 的应用程序之一,即将进入 Web 的 GoodNotes.

他们在创建了一个拥有令人难以置信的功能的 iOS 应用程序的十年中进行了投资,拥有 4.8 星的评级.

他们决定是时候将他们的应用程序扩展到非 iOS 用户了.

而不是必须进行一次令人难以置信的代码重写,而且还必须进行单独的维护,他们决定通过 WebAssembly 重用他们的 Swift 投资.

这意味着他们十年的工作可以重用,同时最大限度地减少维护成本.

他们说的最喜欢的事情之一是”我们的 iOS 开发人员每天都会为我们的 Swift 代码库做出一些新的贡献.我们的 Web 应用程序也会受益于此.”

就其技术堆栈而言,他们正在利用 Swift on WebAssembly,React 作为其 UI 框架,以及 PWA 进行可安装性.

他们在 React 中做了周围的 UI,并且有一个连接到 Swift 引擎的中央画布.

例如,当用户点击”添加页面”之类的内容时,它会从 React 中的单击处理程序调用到 Swift 代码库中,以添加页面,然后使其准备好输入.

他们使用的工具链称为 SwiftWasm.

您可以在 swiftwasm.org 上开始使用它.

该工具链包括 JavaScript kit,它使您的 Swift 代码可以通过绑定与 JavaScript 交互,并转换类型和对象.

它还提供了 Carton,它为类似于 webpack 的东西提供了 Swift 替代方案.

它使您可以轻松地捆绑和部署应用程序,同时还将您的代码发送到其他平台.

与任何内容一样,都有一些开发人员应该知道的限制.

我想明确一点,这不是一个神奇的按钮,可以使您的 Swift 应用程序直接在 Web 上运行.

虽然它比重写快得多,但它并不是零工作量.

Swift 代码和 SwiftUI 应该运行良好.

但是,存储,UI kit,网络和文件之类的东西需要使用 Web 替代方案.

尽管如此,如果您是希望扩大市场的 Swift 开发人员,那么这就是您的时刻.

WebAssembly 标准本身的进展情况

那么,现在我想从任何特定的语言中退后一步,并更新一下 WebAssembly 标准本身的进展情况.

在过去,曾讨论过 WebAssembly 线程和 SIMD 如何为性能敏感的工作负载提供 10 倍或更高的改进.

他们正在继续扩展更多 SIMD 指令,以进一步最大化性能.

TailCalls 提案是功能编程语言的关键优化,可实现更好地支持使用协程的 C++程序.

Memory64提案使应用程序能够引用超过 4GB 的内存,更容易移植 64 位体系结构的代码.

最后,JavaScript Promise Integration API使同步代码可以访问异步 API,而无需进行大量的代码大小或性能开销.

如果您要制作假设同步环境的代码与 Web 一起工作的代码,这是一个大问题.

您可能还记得在去年的 Google I/O 上,计划将 Java,Kotlin 和 Dart 等新语言带到 Web 的计划.

在过去的一年中,WebAssembly 社区一直在忙于实现这一目标.

因此,让我们看看我们构建了什么以及这种新技术对 Web 和本机移动平台的开发人员意味着什么.

WebAssembly 在使用 C 和 C++的开发人员中获得了成功,以及围绕 Rust 的不断增长的社区.

在这些语言中,开发人员负责在应用程序完成使用后释放内存中的对象,从某种意义上说,这类语言是 WebAssembly 标准的主要重点,我们称之为 WebAssembly MVP,部分原因是因为这些语言是许多大型桌面应用程序所编写的语言,也因为在开发 WebAssembly 标准时,这些语言有一些更简单的要求.

另一类语言代表开发人员管理内存.

语言自己的运行时会自动查找并释放应用程序不再使用的内存.

如果您正在构建 Web 或移动应用程序,则此类语言非常有趣,因为 JavaScript 是 Web 自己的 API 的语言.

并且 Kotlin 和 Dart 在构建跨平台本机移动应用程序的开发人员中越来越受欢迎.

那么,我们想弄清楚如何以一种高性能的方式将 Web 平台扩展到使用这些语言编写的应用程序.

让我们看看我们如何做到这一点.

当 Web 应用程序在浏览器中启动时,它会为其 JavaScript 代码和一些热内存提供上下文.

JavaScript 内存是垃圾收集的,因此浏览器后台有一个垃圾收集器.

现在,当应用程序实例化 WebAssembly 模块时,它会请求并分配一块线性内存区域供其自己使用.

如果开发人员使用的是 C 或 C++之类的语言,则 WebAssembly 模块将使用其中一些内存用于动态堆.

开发人员将在使用后处理释放对象.

另一方面,如果开发人员想要使用管理内存语言,则 WebAssembly 模块将需要包含该语言作为垃圾收集器代码来管理堆,并自动释放未使用的内存.

这种方法存在两个主要问题.

  1. 明显的膨胀.

WebAssembly 模块必须每次加载应用程序时都发送并实例化垃圾收集器.

这会增加模块大小并延迟应用程序启动,尽管所有符合标准的浏览器都已经包含了应用程序可以使用的垃圾收集器.

另一种膨胀形式来自开发人员需要在决定其模块所需的内存量时具有一种类似的预知能力.

为了避免崩溃,通常要做的事情是设置最大内存大小,该大小仅略大于您预期的内存需求的上限.

这会给实现带来更大的压力,因为它们必须将应用程序的 JavaScript 和 WebAssembly 内存与用户可能正在使用的其他应用程序和选项卡所需的内存分开管理.

  1. 我称之为分裂大脑问题.

在此体系结构中,这两个内存及其垃圾收集器彼此一无所知.

这意味着开发人员需要小心地设计其应用程序,以避免在 JavaScript 垃圾收集器来到并释放 WebAssembly 侧仍然需要的内存时发生损坏,反之亦然.

所有这些加起来都是开发人员必须自己做的更多簿记,这在某种程度上破坏了首先使用管理内存语言的整个原因.

但是,即使将所有对象放在一侧,即 WebAssembly 侧,也无法避免处理 JavaScript 堆.

这是因为 Web API.

Web API 被指定为接受和返回 JavaScript 对象,这些对象自然位于 JavaScript 堆上,并由 JavaScript 垃圾收集器收集.

在 WebAssembly 的原始版本中,这意味着在调用 Web API 时,需要在 WebAssembly 和 JavaScript 之间来回复制数据.

图形 API(例如 Dom,Canvas,WebGL 和 Web GPU)尤其受此影响,因为在某些情况下,它们需要每帧调用数百次或每秒调用数千次,严格的延迟要求以避免用户可见的 jank.

最终的结果是,即使我们为代码构建了快速的编译目标,许多框架和应用程序也会产生比它们在本机移动平台上产生的更多的 jank 体验.

那么我们如何解决这个问题?

好吧,WebAssembly 社区创建了一个新的扩展,实际上在 JavaScript 和 WebAssembly GC 模块之间共享一个联合堆.

现在,您的管理内存代码可以在此共享堆上分配模块.

当浏览器的垃圾收集器来时,JavaScript 和 WebAssembly GC 对象将一起进行垃圾收集.

这意味着没有膨胀.

您的 WebAssembly 模块不必在应用程序中发送其自己的完整垃圾收集器实现.

您的 WebAssembly 应用程序可以更轻松地根据需要增加或减少其内存消耗,就像 JavaScript 应用程序一样.

包括 WebAssembly GC 模块,创建对象的堆与 JavaScript Web API 查找它们的堆相同,并且返回值也很容易传递,所有这些都不需要过多的复制.

因此,这就是 WebAssembly GC,现代管理内存语言的更小二进制文件,与 JavaScript 代码和 Web API 以及动态可调整大小的内存占用相比,更快的互操作性.

Flutter,Android 和 Kotlin 多平台

有了 WebAssembly GC,Web 终于可以向我们的 Flutter,Android 和 Kotlin 多平台应用程序开发人员表示欢迎.

让我们看看 WebAssembly 对您意味着什么.

早期数据显示,WebAssembly GC 现在可以在浏览器中运行从这些语言编译的代码比将它们编译为 JavaScript 运行时快两倍.

从用户的角度来看,这种性能水平越来越难以区分,与本机移动平台上看到的相同.

我们正在谈论每秒 120 帧的应用程序,单个毫秒帧更新时间.

现在,我们可以想象一个世界,在这个世界中,跨平台框架可以使用本机移动平台和 Web 构建应用程序,而用户在哪里找到您的应用程序时,其功能和性能没有任何区别.

开发人员体验也会变得更好.

以前,开发人员必须构建单独的本机 Android 和 iOS 应用程序,以及 Web 应用程序,以覆盖最广泛的用户集.

跨平台框架,例如 Kotlin 多平台移动,使开发人员可以在单个代码库中编写其移动应用程序的业务逻辑,该代码库编译为 Android 和 iOS,同时使用平台本机框架和小部件实现其用户界面.

但是,将此跨平台功能扩展到 Web 遇到了一些挑战.

很长一段时间以来,您无法将移动语言(例如 Kotlin)编译为 Web.

最多,您可以将其转换为 JavaScript,然后在浏览器中运行该 JavaScript.

这种方法产生的 Web 上的应用程序对用户来说并不像本机移动平台上那样快速和平滑.

现在,借助 WebAssembly 对管理内存语言的新支持,跨平台应用程序也可以直接编译为所有三个平台的本机运行时,从而使开发人员可以访问 Web 的覆盖范围和即时启动,并为用户提供快速和平滑的体验无论他们在哪里找到您的应用程序.

Kotlin 社区还受益于 UI 框架,例如 Compose,它可以帮助开发人员共享大部分其 UI 代码,以及性能水平与本机平台相匹配的本机平台.

关于 Jetbrain 与 WebAssembly

在 JetBrains,WebAssembly 是一项有前途的技术.

就在不久前,发布了 Kotlin 编译器的 WebAssembly 目标的实验版本.

我们在 Kotlin Wasm 的未来中看到了很多潜在的用例,从在浏览器中运行的高性能 Web 应用程序,到构建快速的无服务器功能.

向您展示 Kotlin Wasm 未来的一个具体示例.

在这里,您可以看到使用 Jetpack Compose 构建的应用程序,Jetpack Compose 是 Google 为 Android 创建的声明性和现代 UI 框架.

您可能实际上已经在 Android 上看到了这个特定的应用程序.

现在,在 JetBrains,他们正在努力将 Jetpack Compose 带到除 Android 之外的多个其他平台,例如桌面,iOS 和 Web.

实际上,这意味着您可以使用 Jetpack Compose 的所有 API,这些 API 可能来自于为 Android 开发的经验,并将其用于其他平台.

Compose 的 Web 目标是构建在 Kotlin Wasm 之上的.

它仍处于实验阶段.

但是,让我向您展示我们已经可以做些什么.

您可以在 kotlinlang.org 上了解有关 Kotlin 在 Web 上运行的更多信息.

他们不仅使 Android 应用程序多平台化,Flutter 开发人员多年来一直在使用 Flutter 来针对 Android,iOS 和 Web.

在 Web 上,Flutter 开发人员也必须转换为 JavaScript 才能在浏览器中运行.

但是,他们也为 Flutter web 解锁了更快的性能.

今年首次,直接将 Dart 代码编译为浏览器中快速高效的 WebAssembly 代码.

您可以在 flutter.dev/wasm 上阅读有关 Flutter web 提供的令人兴奋的新性能提升的更多信息.

在开放的 Web 上,您的应用程序距离新用户只有一步之遥,他们可以像共享 Web 页面一样轻松地发现它并共享它,而没有任何商店阻碍您的盈利能力.

总结

跨平台开发的生产力,原生移动应用程序的性能以及 Web 的开放性 - 这就是我们选择 WebAssembly 的原因.

作者

1uciuszzz

发布于

2023-05-16

更新于

2023-05-16

许可协议

评论