理解微信小程序的双线程模型 (2)

理解微信小程序的双线程模型

React Fiber就是利用idle时间进行分片任务处理。

后来,HTML5 引入了 Web Worker,提供多线程执行 JavaScript 代码的能力,但是与其他编程语言不同的是,Worker 线程与主线程并不是平行的,而是一种主从( Master-Slave)多线程模型。

Worker 内的 JavaScript 代码不能操作 DOM,可以将其理解为线程安全的。要记住这一点,这是后面讲小程序双线程模型一个重要的基础。

那么为什么微信小程序不直接使用浏览器的线程模型呢?这需要从产品和技术两个角度对比小程序与 Web 网站的差异。

为什么小程序不使用浏览器的线程模型

我刚接触小程序开发时,经常“嫌弃”它跟 Web 相比阉割弱化的能力、跟 Vue 相比简单到过分的语法等。当时,我几乎觉得小程序就是微信仗着自己庞大的用户量搞技术垄断。

但是,随着对技术和产品的不断深入理解,我对小程序的态度也有了转变,由“嫌弃”变成了敬佩,因为在充分理解了小程序的产品定位后,我发现双线程模型是在小程序这类产品场景下的最优解。那小程序是一款什么样的产品呢?

小程序的宿主是微信,但是小程序版本的迭代是独立的,升级更新不依赖宿主,这一点跟 Web 网站是相同的。也就是说,小程序沿袭了 Web 的某些优势,但它并不是 Web,目前 Web 相关的技术已经相当全面,能够承载一些非常庞大的应用程序,比如 3D 地图、游戏等。

而小程序的定位是小而美、用完就走,不追求在微信中实现全部的 Web 能力,所以和 Web 来比能力上肯定差一些,同时具备一些微信提供的原生能力,比如原生组件、系统级别和微信生态的 API 等等。

另外,“小程序-微信”的关系跟“网站-浏览器”的关系不同,前者更接近 CodePen、JSFiddler 这类在线编程平台(课里简称平台)中每个程序案例(简称案例)与平台的关系。

从技术的角度上,平台最核心的一个考量点是为案例提供足够能力的前提下,保证案例的逻辑不会危及平台的安全。想象一下,假如你能够在 CodePen 上编写一个程序来获取 CodePen 的私密信息,可能第二天 CodePen 就崩溃然后炒掉所有员工。

在这样的产品基调下进行技术选型,接下来就是架构师和程序员的工作了。

还是以 CodePen 为例,假如让你来设计这样的编程平台,你会用什么技术呢?可能你第一个想到的是用 iframe,因为可以在 iframe 内使用全部 Web 能力。事实上 CodePen 确实用 iframe 来呈现程序的效果,但是并不会把输入的 JavaScript 代码完全拷贝到 iframe 内运行,而是代码会经过一次编译流程之后才会被注入 iframe 内。这样做的出发点主要是基于安全的考虑,在编译过程中将一些危险的代码剔除;其次这样做还能在平台中支持更多语言,比如typescript。当然,还有性能,性能问题是 iframe 老生常谈的问题了,我就不多说了。

所以,不仅要使用 iframe,还需要引入额外的 JavaScript 编译器。CodePen 一定要保证每个案例的 JavaScript 代码是线程安全的,最基本的就是要禁止程序操作CodePen 网站的 DOM ,实现这一点有两个方法:

一个是 Web Worker;

另一个是使用 Shadow DOM。

Web Worker 是线程安全的,Worker 内的 JavaScript 代码无法获取 Window 和 Document 对象,也就无法操作 DOM。除此之外,由于 Worker 的线程安全特性,Worker 内的代码运行过程中不会阻塞外层的 GUI 渲染线程,两者可以并行。

Shadow DOM 是 Web Components 规范的一部分,将 ShadowRoot 的模式设置为 closed 就可以禁止获取到 ShadowRoot 节点,从而也无法操作其内部的 DOM。

两者相比,Shadow DOM 的兼容性比 Web Worker 更差,距大规模使用的日期还很遥远,所以 Web Worker 的方案更现实一点。

这样就形成了一个简易的双线程模型:Worker 线程负责计算,将结果通过 postMessage 传递给主线程,主线程负责渲染。

理解微信小程序的双线程模型

但是这个模型存在比较严重的性能问题,Web Worker 非常耗费资源,除去计算消耗以外,与主线程的通信过程对性能的损耗也非常严重。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwfwjd.html