师夷长技以制夷:跟着PS学前端技术(二)

简介: 师夷长技以制夷:跟着PS学前端技术(二)

3.2 发挥WebAssembly的威力

WebAssembly对于在JavaScript中重新创建Photoshop的计算密集型图形处理是一个不可或缺的要素。Adobe使用Emscripten编译器将他们现有的C/C++代码库移植到WebAssembly模块中。

兼容性

还是熟悉的配方,我们通过caniuse来查看,桌面浏览器对WebAssembly的支持程度。哇塞,形势一片大好。各大厂商都意识到这个神兽能给我们带来更多意想不到的可能性。

其实,暂且不看市面上公司如何使用,从各个厂商的积极程度也侧面反应了,我们的预期。

image.png

几个WebAssembly的功能至关重要:

  • 线程 - Photoshop使用工作线程以并行方式执行任务,比如处理图像块
  • SIMD - SIMD矢量指令加速像素操作和过滤。
  • 异常处理 - C++异常广泛用于整个Photoshop的代码库。
  • 流式实例化 - Photoshop的80MB+ WASM模块需要流式编译。
  • 调试 - Chrome的WebAssembly在DevTools中的调试支持是非常有价值的。

如果大家对WebAssembly还不是很了解的话,可以翻阅我们之前写的浏览器第四种语言-WebAssembly。针对wasm的概念性东西这里就不在过多介绍了。在里面我们还介绍了利用Emscripten实现了 将C/C++代码编译为WebAssembly

并且,在我们之前还介绍过,CJS代码之间的互操作。感兴趣的可以参看WebAssembly-C与JS互相操作

而我们来讲讲SIMD的东西。


SIMD

SIMD代表单指令,多数据。是Single Instruction, Multiple Data的缩写。

SIMD操作这个术语指的是一种计算方法,它能够通过单个指令来处理多个数据。相比之下,传统的顺序方法使用一条指令来处理每个单独的数据,这被称为标量操作

以简单的加法为例,下面说明了标量操作SIMD操作之间的差异。

image.png

使用传统的标量操作,必须依次执行四个加法指令才能获得如图(a)所示的总和。与此同时,SIMD只使用一条加法指令就能获得相同的结果,如图(b)所示。由于处理相同数量的数据所需的指令更少,SIMD操作比标量操作具有更高的效率

这里简单的说一句题外话:标量这个词是不是感觉似曾相识。其实,我们在介绍Rust数据结构的时候就有过接触呢。

image.png

这下估计就知道标量操作就是单一操作了。

SIMD指令是一类特殊指令,通过同时对多个数据元素执行相同的操作,来充分利用应用程序中的数据并行性。计算密集型应用程序,如音频/视频编解码器、图像处理器,都是利用SIMD指令来加速性能的示例。

SIMD的限制

尽管SIMD操作具有能够在一条指令中处理多个数据的优势,但它们只能应用于特定预定义的处理模式。下图展示了一个这样的模式,在该模式中,所有数据都执行相同的加法操作

image.png

SIMD操作不能用于以不同方式处理多个数据。下图中提供了一个典型的示例,其中一些数据需要相加,而其他数据需要相减、相乘或相除。

image.png

SIMD操作就是需要所有数据都是执行相同的操作)

想了解更多关于SIMD概念性的东西,可以参看SIMD基础介绍 (需要🪜)

由于SIMDwasm的特性,而我们的关注点又是浏览器环境,我们就挑一个我们熟悉的浏览器chrome来描述一下,所以我们看看V8是如何支持这个特性的。(V8chrome/chromium的关系我们之前聊过)

由于可编译为wasm的语言过于多,例如C/C++/Rust甚至TypeScript。所以,我们就挑一个我们比较感兴趣的语言来说明。

将Rust代码编译为WebAssembly SIMD

当将Rust代码编译为WebAssembly SIMD目标时,我们需要启用与Emscripten中的simd128 LLVM特性相同的特性。

当启用msimd128特性时,默认情况下启用LLVM的自动矢量化器,即在优化级别-O2-O3时启用。

如果可以直接控制rustc标志或通过环境变量RUSTFLAGS,可以传递-C target-feature=+simd128

RUSTFLAGS="-C target-feature=+simd128" cargo build

或者

RUSTFLAGS="-C target-feature=+simd128" cargo build

例如,考虑以下函数,该函数将两个输入数组的元素相乘并将结果存储在输出数组中。

pub fn multiply_arrays(out: &mut [i32], in_a: &[i32], in_b: &[i32]) {
  in_a.iter()
    .zip(in_b)
    .zip(out)
    .for_each(|((a, b), dst)| {
        *dst = a * b;
    });
}

如果没有传递msimd128特性,编译器会生成以下WebAssembly循环:

(loop
  (i32.store
    … 获取`out`中的地址 …
    (i32.mul
      (i32.load … 获取`in_a`中的地址 …)
      (i32.load … 获取`in_b`中的地址 …)
)

但是,当使用msimd128特性时,自动矢量化器会将其转换为包含以下循环的代码:

(loop
  (v128.store align=4
    … 获取`out`中的地址 …
    (i32x4.mul
       (v128.load align=4 … 获取`in_a`中的地址 …)
       (v128.load align=4 … 获取`in_b`中的地址 …)
  )
)

循环体的结构相同,但在循环体内部使用SIMD指令加载、相乘和存储四个元素


启发&应用场景

与其说是启发,倒不如说是,WebAssembly能够给我们带来多大的惊喜。在之前的文章中,我们聊过WebAssembly在哪些场景下能够大放异彩。 而今天既然聊到了WebAssembly -SIMD,那我们到底看看它是否还有绝活


WebAssembly SIMD提案旨在加速高计算应用程序,如音频/视频编解码器、图像处理应用程序、加密应用程序等。

MediaPipe是一个用于构建多模式(例如视频、音频、任何时间序列数据)应用机器学习管道的框架。

其中一个视觉效果最吸引人的演示,可以很容易地观察到SIMD带来的性能差异,是一个仅使用CPU构建的手部跟踪系统。没有启用SIMD时,在现代笔记本电脑上只能获得大约14-15帧每秒(FPS),而在Chrome Canary中启用SIMD后,您可以获得更平滑的体验,帧率可达38-40帧每秒。

image.png

OpenCV,这是一个流行的计算机视觉库,也可以编译成WebAssembly。

OpenCVIntel开源计算机视觉库。它由一系列C 函数和少量C++ 类构成,实现了图像处理和计算机视觉方面的很多通用算法。

其中它有一个WebCamera的项目,如下图。做了一下用于图像和视觉处理的工具。

image.png

此图,就是用于用摄像头识别银行卡中的帐号数据,并对齐提取。

image.png

那是不是,在我们遇到类似的功能点时,我们在已经引入到对应的视觉处理工具后,效果还没达到我们的心里预期,那WebAssembly SIMD不就有了用武之地了吗。

不仅,视觉处理,还有音频处理也是相同的道理。这里就不展开说明了。


3.3 将sRGB替换为P3

还有老样子,让我们can一下。

image.png

DCI-P3,有时也称为P3Display P3DCIDigital Cinema Initiatives的缩写,是数字电影领域的一个标准。

sRGB代表标准红绿蓝,是一种颜色空间,也是一组特定的颜色,由惠普和微软于1996年创建,旨在标准化电子设备中显示的颜色。sRGB是目前最流行的颜色空间,用于Windows、大多数网络浏览器以及大多数控制台和个人电脑游戏,除非它们支持高动态(HDR)。

显示器或其他设备的色域告诉我们设备可以重现哪个颜色空间,以及它可以在0-100%甚至更高的范围内呈现多少颜色。除了sRGB,其他常见的颜色空间还包括Adobe RGBP3,它们都比sRGB更大,即包含更多颜色

下面是XY色度图,代表了人眼可以看到的所有颜色范围。在那个颜色范围内,有一个白色的三角形,它勾勒出sRGB标准所包括的颜色。例如,如果我们试图在sRGB显示器上查看超出该三角形范围的颜色的图像,那些额外的颜色会显得不准确和饱和不足

image.png

sRGB vs P3

虽然sRGB是标准,但其他颜色空间也可能更具吸引力。P3表现色域比sRGB更大(覆盖更多颜色)。

P3显示的色域比sRGB显示器宽50%

image.png

白线显示了sRGB的边缘。它上面右边的部分是Display-P3颜色,而这些颜色在sRGB中是不可用的。请注意,绿色扩展得很大,而蓝色扩展则远远不及。

sRGBP3之间的另一个区别是P3可以处理10位颜色

Photoshop使用新的color()函数和Canvas API来释放P3的全部光彩,实现更准确的颜色呈现。

color: color(display-p3 1 0.5 0)

上面的语法等同于旧有的css表示颜色的语法。

  • hsl(42, 70%, 50%)
  • rgb(3, 5, 11)
  • #abc

如果我们想使用p3可以使用@supports功能查询。

/* sRGB颜色。 */
:root {
    --bright-green: rgb(0, 255, 0);
}
/* Display-P3颜色,如果支持的话。 */
@supports (color: color(display-p3 1 1 1)) {
    :root {
        --bright-green: color(display-p3 0 1 0);
    }
}
header {
    color: var(--bright-green);
}

启发

如果我们在项目中,想要实现一下对色彩饱和度有强烈要求的功能,那么我们就可以使用color(display-p3)来增强我们的项目。虽然,写不出五彩斑斓的黑,红的发紫的白。但是这也算是我们扩展应用功能的一把利器。

好钢要用在刀刃上


3.4 利用Web组件提升UI的灵活性

Photoshop利用基于Lit构建的标准化Web组件策略,可以实现应用程序之间的UI一致性。

image.png

Photoshop的用户界面元素来自AdobeSpectrum Web Components库,该库实现了Adobe的设计系统。

Spectrum Web Components具备以下特点:

  • 默认支持辅助功能 — 开发时考虑了现有和新兴的浏览器规范,以支持辅助技术。
  • 轻量级 — 使用LitElement实现,减小了额外开销。
  • 基于标准 — 基于Web Componment标准,如自定义元素和Shadow DOM 构建。
  • 框架无关 — 由于浏览器级别的支持,可以与任何框架一起使用。

此外,整个Photoshop应用程序都是使用基于LitWeb组件构建的。Lit的模板和虚拟DOM diff使得UI更新更加高效。Web组件的封装性也使得在需要时可以轻松集成来自其他团队的React代码。

我们在之前的文章中也有对Lit有过涉猎,本人也在项目中也有对应的简单应用。咋说呢,感觉Lit的封装还是很nice的。但是,如果硬要刨根问底的话,其实还是要从Web Componment来讲。

如果想了解Lit可以通过Lit 官网去学习和查阅。这里就不在多讲。

虽然,现在Vue/React等,框架大行其道,但是Web Componment中的一些理念和使用方式是最贴合浏览器渲染机制的。然后,由于篇幅有限,我们打算,针对Web Componment会做一次深度的解析和教学。

启发

虽然,不知道PS团队,不知出于何种目的,选用了Lit作为了构建前端页面的UI库。但是,想象一下,如果现在我们有一个大前端团队,由于历史包袱原因,即有React,又有Vue团队。现在有一个庞大的功能需求需要全团队配合去做。那是不是利用Lit或者Web Componment可以解决这个痛点。

但是呢,使用Lit只是一个跨语言合作的一个可行方案,我相信市面上肯定有很多解决方案,例如:Veaury

image.png

还有很多巨石应用的解决方案。这里也不过多展开了。


4. 优化Photoshop在浏览器中的性能

尽管新的Web功能提供了基础,但像Photoshop这样的高强度桌面应用程序仍然需要进行大量的跟踪和性能优化工作,以提供一流的在线体验。

4.1 使用Service Workers缓存资源和代码

Service Workers允许Web应用将其资源、代码和其他资源本地缓存,以在初始访问后加载速度更快。虽然它还不是一个完全离线可用的应用程序,但Photoshop已经利用Service Workers来缓存其WebAssembly模块、脚本和其他资源。

image.png

Adobe使用Workbox库更轻松地将Service Worker缓存集成到他们的构建过程中。

针对Worker呢,我们之前的文章就有过介绍。

image.png

分别对Web WorkerService Worker做了一次比较透彻的分析。

然后呢,其实在Service Worker始终有一种欲罢不能的感觉。就像上面说的,Photoshop是借助了Workbox实现了资源的本地缓存。同时,我也是第一次听说这个技术(Workbox),然后就这两天开始着手找资料学习和研究。发现,其中的很多点都很喜欢,然后也是有很多的点可讲。但是呢,由于现在有些东西还未亲身实践,所以有些想着,等我实践完然后准备写一篇或者多篇的文章,深度解析一下这个东西。

在这里,我就偷个懒了哈,不过更文列表中已经有计划了。优先级还很高呢。



4.2 V8对已缓存资源的优化

当资源从Service Worker缓存中返回时,V8会进行一些优化:

  • 在安装期间缓存的资源会被急切地编译,并立即进行代码缓存,以保持一致、快速的性能。
  • 通过Cache API缓存的资源在第二次加载时进行了优化缓存,比通常的缓存速度更快。
  • V8会检测已缓存资源的重要性,并更积极地进行编译。

这些优化允许对Photoshop庞大的缓存Wasm模块进行优化。

image.png


4.3 流式传输和缓存大型WebAssembly模块

Photoshop的代码库需要多个大型WebAssembly模块,其中一些超过80MBV8Chrome中的流式编译支持使这些大型模块可以在性能方面进行有效处理。

image.png

也就是说,V8不用讲wasm模块全盘接收,再开启编译模式。这样在很大程度上节省了时间,尤其在遇到大文件的时候。

此外,第一次从Service Worker请求WebAssembly模块时,V8会生成并存储一个优化版本以进行缓存,这对于Photoshop庞大的代码尺寸至关重要。

4.4 用于并行图形操作的多线程

Photoshop中的许多核心图像处理操作,如像素变换,可以通过跨线程并行执行来大幅加速。WebAssembly的线程支持可以利用多核设备进行计算密集型图形任务

这允许Photoshop在转移到WebAssembly后,使用与桌面相同的多线程方法来处理性能关键的图像处理函数。

4.5 用于优化的WebAssembly调试

在开发过程中,强大的WebAssembly调试支持对于诊断和解决性能瓶颈至关重要。

Chrome DevTool的能力可以对WASM代码进行性能分析、设置断点,并检查丰富的变量,这与JavaScript的调试性质相似。

image.png


5. 使用TensorFlow.js集成本地设备上的机器学习

最近版本的Web上的Photoshop包括使用TensorFlow.js的AI功能。在设备上运行模型而不是在云端改善了隐私、延迟和成本。

image.png

TensorFlow.jsGoogle推出的针对JavaScript开发者的开源机器学习库,能够在浏览器中客户端运行。它是用于Web机器学习的最成熟选择,具有全面的WebGLWebAssembly后端操作支持,未来还将提供WebGPU后端选项,以在浏览器中获得更快的性能,以适应新的Web标准的发展。"

"选择主题"功能利用机器学习自动提取图像中的主要前景对象,大大加速了复杂的选择操作。


image.pngimage.png

image.png

为了实现本地执行,该模型从TensorFlow转换为TensorFlow.js

// 加载“选择主题”模型
const model = await tf.loadGraphModel('select_subject.json');
// 在图像张量上运行推理
const {mask, background} = model.execute(imgTensor);

Adobe和Google合作开发了一个用于Emscripten的代理API,以解决Photoshop的WebAssembly代码和TensorFlow.js之间的同步问题,从而实现了这两个框架的无缝集成。

“由于Google团队通过其各种支持的后端(WebGL、WASM、Web GPU)提高了TensorFlow.js的硬件执行性能,这导致模型的性能改进在30%到200%之间(尤其是对于倾向于获得最大性能提升的较大模型而言),在浏览器中几乎实时性能。”


启发

这个点,算是继wasm在浏览器中实现,又一个让我眼前一亮的特性。现在大家都在卷各种大模型,国内国外都是如此,我们公司也有自己的AI团队。而大部分的开发模式,基本上都是将AI模型配置到后端,然后前端页面都是通过异步接口进行传值处理。其实这和旧有的前端开发模式没有任何的改变。

但是,在PS团队实现了基于TensorFlow.js的前端AI模型,那是不是变现的说,万物即可AI,并且在前端也会有一席之地。

等着,给我一段时间,到时候给大家出一篇在前端界面中使用TensorFlow.js的教程。(这个是真心喜欢研究的东西)


后记

写到这里,其实里面的内容过于多,本来不想再继续聒噪了,但是还是有感而发。

人人都说前端已死,但是你如果看到上面的一些技术和特性,你还会有这种感觉吗。

不要学着别人去,自怨自艾,只有自己内心渴望一个东西,你才会有勇气和动力去面对和征服它。

分享是一种态度

全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。

相关文章
|
2天前
|
前端开发 JavaScript UED
前端技术:引领数字时代的交互之美
前端技术:引领数字时代的交互之美
|
2天前
|
XML 前端开发 JavaScript
前端技术的演变与实战应用
前端技术的演变与实战应用
|
19天前
|
前端开发 JavaScript 关系型数据库
从前端到后端:构建现代化Web应用的技术探索
在当今互联网时代,Web应用的开发已成为了各行各业不可或缺的一部分。从前端到后端,这篇文章将带你深入探索如何构建现代化的Web应用。我们将介绍多种技术,包括前端开发、后端开发以及各种编程语言(如Java、Python、C、PHP、Go)和数据库,帮助你了解如何利用这些技术构建出高效、安全和可扩展的Web应用。
|
1月前
|
XML 前端开发 JavaScript
AJAX 前端开发利器:实现网页动态更新的核心技术
**AJAX** 允许网页在不刷新的情况下更新内容,实现异步与服务器交换数据。通过JavaScript的XMLHttpRequest对象,可发送和接收数据。当用户触发事件(如点击),函数向服务器发送GET请求,服务器响应后更新指定HTML部分。AJAX并非编程语言,而是利用浏览器内置对象、JavaScript和DOM技术。核心是XMLHttpRequest对象,它有多种方法(如`open()`和`send()`)和属性(如`onreadystatechange`、`readyState`和`status`)来处理请求和响应。
58 2
AJAX 前端开发利器:实现网页动态更新的核心技术
|
1天前
|
机器学习/深度学习 人工智能 前端开发
探索未来:2024年前端技术趋势解读
探索未来:2024年前端技术趋势解读
13 4
|
2天前
|
前端开发 JavaScript UED
Web前端开发:探索技术与艺术的交融
Web前端开发:探索技术与艺术的交融
8 1
|
15天前
|
前端开发 算法 JavaScript
如何优化前端性能:探索图片压缩与延迟加载技术
本文深入探讨了前端性能优化中的关键问题:图片压缩与延迟加载技术。通过介绍图片压缩的原理和方法,并结合实例说明了如何有效减少图片大小、提升加载速度;同时,详细解析了延迟加载技术的实现原理及其在提高页面加载性能中的作用,为前端开发者提供了实用的优化方案。
|
29天前
|
编解码 前端开发 JavaScript
探索前端开发中的新趋势:WebAssembly 技术应用与展望
本文将深入探讨前端开发中的新趋势——WebAssembly 技术,介绍其在前端领域的应用场景和优势,并展望未来在前端开发中的潜在影响。通过对 WebAssembly 技术的原理解析和实际案例分析,帮助读者更好地了解并应用这一新兴技术。
|
1月前
|
前端开发 JavaScript NoSQL
从前端到后端:构建全栈应用的技术挑战与解决方案
在当今互联网时代,全栈开发成为越来越受欢迎的技术趋势。本文将深入探讨从前端到后端的全栈开发过程中所面临的技术挑战,并提出相应的解决方案,涵盖前端框架选择、后端技术架构、数据库设计以及跨平台兼容性等关键问题。
|
1月前
|
前端开发 JavaScript NoSQL
从前端到后端:构建全栈开发的技术生态
本文将探讨如何在全栈开发中构建完整的技术生态,从前端到后端各个层面进行深入剖析,讨论不同技术之间的协作与整合,为开发人员提供全面的指导与启示。