likes
comments
collection
share

132-打造一个轻量的小程序引擎玩玩

作者站长头像
站长
· 阅读数 13

第二十六届|前端互动专场,了解互动编程|互动性能|互动美术|地图世界等等的可能性,5-15 下午直播,5 位讲师(蚂蚁/淘宝/字节等等),点我上车👉 (报名地址):

132-打造一个轻量的小程序引擎玩玩

所有往期都有全程录播,可以购买年票一次性解锁全部

👉更多活动


正文如下

本文是第十七届 - 前端早早聊框架专场,也是早早聊第 121 场,来自自由职业 - 132 的分享

132-打造一个轻量的小程序引擎玩玩

自我介绍

哈喽,大家好!俺是 132,前面有几位讲师讲了很多领域,包括跨端,web GL 游戏引擎,还有微前端,就差小程序了,小程序这套架构还是恨套路的,让我们一起探讨一下下

132-打造一个轻量的小程序引擎玩玩

先做一下自我介绍,我是伊撒尔,简称 132,写过很多框架和轮子,比如 fre,berial,eplayer 等,大家平时有什么想问我的,可以去 fre 仓库的 disscussions 中随便发,俺都是不介意的

132-打造一个轻量的小程序引擎玩玩

我们的小程序框架的底层,我把它分为四个部分,主要是

  • 多线程模型
  • runtime 框架
  • js 沙箱
  • 其他

我们一个一个来


多线程模型和线程通信

132-打造一个轻量的小程序引擎玩玩

多线程模型

132-打造一个轻量的小程序引擎玩玩 多线程模型是一个非常常见的 UI 模型,包括 RN、flutter 统统都是使用的这个模型,小程序也不例外

它们其实只是线程主体的不同,比如 RN 主要是 shadow tree 和 jscore,而 flutter 则是 skia 和 dart engine,小程序则是 webview 充当渲染层,js engine(或 worker)充当逻辑层

尽管本质一样,但因为业务场景的不同,小程序的诉求却和 RN/flutter 完全不同

在 RN 中,app 作为一个主体,我们更乐意分配更多资源,以至于 RN 一直在跑 react 这种 runtime 浪费的框架,在过去,这被认为是值得的

但是小程序与之相反,它作为 app 的附属品,我们不乐意给小程序分配更多资源,不乐意分配内存,不乐意分配更多线程,所以我们这次分享的前提是

基于最小分配的前提,探讨小程序的每个环节

请记住前提,然后我们接着往下看


线程通信

132-打造一个轻量的小程序引擎玩玩

说到多线程,我们首先想到的就是多线程的调度和通信,我们先讲通信,通常来说,多线程的非 UI 线程都是没有 dom 环境的,无论是 js 引擎还是 worker

所以为了能跑一个前端框架,我们不得另寻出路,主要方案有三种,其中幻灯片的第二种,写一个 dom 无关的 diff 算法,这是写不出来什么好算法的,所以我们主要看剩下两种思路 132-打造一个轻量的小程序引擎玩玩 幻灯片中,左边的代码是 [ 使用 Proxy 劫持 dom ],右边的是 [ 模拟 dom API ]

这两种思路其实是类似的,模拟 dom API 是最为常见的,比如 react-reconciler,vue3 的 renderer,都是用的这个思路,就是它把用到的 dom API 暴露出来,你在不同的端去模拟 dom 的行为

甚至还有 taro-next,kbone 这种框架,他们模拟了一整个 dom/bom 层

这个思路好处是粗暴方便好用,坏处就是抽象程度低,比如 taro-next 中就用了千行代码做这件事,属于 case by case,没啥逼格

所以我提出了 Proxy 劫持 dom 的思路,其实这个思路在微前端中比较常用,只不过我们现在用 Proxy 不再是劫持一两个 dom 操作了,而是将所有 dom 操作通通记录下来,然后批量发送给 UI 线程

这个实现抽象程度非常高,我使用了不到 200 行代码就可以劫持所有 dom 操作

代码在这里:github.com/yisar/fard/…

除了线程通信,更重要的是线程的调度,因为很重要,我们放到最后说


前端框架

132-打造一个轻量的小程序引擎玩玩 还记得小程序架构的前提吗?没错,就是最小资源分配

因为我们不想给小程序分配过多的资源,所以像 react、vue 这种 runtime 特别重的框架,其实是不适合用作小程序的

甚至 fre 也不适合,因为大家可能对“轻量”这个词有误解,不是代码越少就越轻量,代码量是很重要的一个方面,但是更重要的是代码的内存占用,以及算法的算力和复杂度

fre 虽然代码量少,但它的算法和 vue 是一样的,算力相同,内存占用也不少

132-打造一个轻量的小程序引擎玩玩

所以我们不得不将目光转向 svelte 这类框架,幻灯片可以看到,svelte 通过编译,直接生成原生 dom 操作,没有多余的算法和 vdom

实际上,我们在做性能优化的时候,讲究一个“换”字,react 这种框架,通过浪费 runtime 去做算法,“换”一个最小结果,而 svelte 则是通过编译(浪费用户电脑),去换 runtime


JS 沙箱

132-打造一个轻量的小程序引擎玩玩 然后我们来讲讲沙箱,也就是 js 引擎和 worker,这部分适合语言爱好者

选型

132-打造一个轻量的小程序引擎玩玩 通常来说,一提到 js 引擎,大家都是 v8 v8 v8

但是实际上,v8 是一个高度优化的 JIT 引擎,它跑 js 确实是足够快的,但对于 UI 来说,我们更多要的不是跑得快

132-打造一个轻量的小程序引擎玩玩 实际上,AOT 的语言或引擎更适合 UI 框架,比如 RN 的 hermes,dart 也支持 AOT,它可以编译成字节码,只需要一次构建即可,当然,AOT 也有缺点,就是 热更新 比较难做

另外除了 js 引擎,worker 也是一个非常赞的选择,方便好用,而且还提供了 bom 接口,比如 offscreen canvas,fetch,indexdb,requestAnimationFrame……

总结

132-打造一个轻量的小程序引擎玩玩

哈哈哈总结,我们基于最小分配的前提去设计这个架构,每个环节都选择节省资源的方案

事实上写代码就是这样的,比如我写 fre,那么我追求 1kb,0 依赖,我写业务框架,我追求 0 配置,1mb 的 node_modules 总大小

我写小程序,我追求最小资源分配,不管做啥,有痛点然后有追求然后才有设计


其他

132-打造一个轻量的小程序引擎玩玩

其实小程序还有很多东西可以做,比如现在的小程序都需要兼容微信小程序,也就是类似 wxml,wxss,wxs这些非标准的文件,还要得是个多 Page 的 mpa

比如 ide,我们可以使用 nobundle 的思路来加快构建速度

当然,为了服务业务,在我们公司我没有使用 nobundle

132-打造一个轻量的小程序引擎玩玩

比如剧透一下,我在公司中为了兼容微信小程序,开的新坑

原理是将微信的文件(wxml,wxss,wxs)先编译成可识别的文件(jsx,css,js),然后使用 babel、postCss 去转移,形成一个个 umd 的子应用

然后通过 berial(微前端框架)的路由,沙箱,生命周期,将它们跑在 h5 端,这样就可以在浏览器中模拟和调试啦132-打造一个轻量的小程序引擎玩玩

最后我们通过三张图和一个问题,来补充和结束一下这次分享

第一张图是微信小程序的后台桌面,有没有感觉和操作系统有点像,但其实不是的,操作系统的软件是进程的关系,只能切换,不能共存,而小程序是多进程,这些小程序可以在后台留驻,随时保持唤醒

第二张图是钉钉的仪表盘,这也是小程序最常用的场景,就是和这种一堆子应用的 app

第三张图是 vscode 的插件系统,是的,想不到吧,这玩意也是小程序架构,而且也是同样的思想,我不让你操作 dom

然后最后的问题:canvas 怎么办?

这个问题实际上非常难搞,如果我们使用 worker 作为 js 沙箱还好,有 offscreen canvas 和 requestAnimationFrame

如果我们使用 js 引擎怎么办呢,走上面提到的线程通信成本就太高了,动画走这个通信,等接收到消息,动画已经卡死了

所以还有什么办法,这里不得不再次提多线程的特性,也就是多线程的内存是共享的,我们可以 js 引擎中,将 canvas 整个元素放到堆栈里,然后 UI 线程和 js 线程共享这一块内存

这样就不需要走线程通信了,适合 canvas,动画这种场景 132-打造一个轻量的小程序引擎玩玩 演讲过程中有点紧张,废话比较多,建议回放 2 倍速,这篇文章是我重写的,精简了很多,希望对大家有所帮助

最后,蟹蟹大家,再贱!


别忘了 5-15 的第二十六届|前端互动专场,了解互动编程|互动性能|互动美术|地图世界等等的可能性,5-15 下午直播,5 位讲师(蚂蚁/淘宝/字节等等),点我上车👉 (报名地址):

132-打造一个轻量的小程序引擎玩玩

所有往期都有全程录播,可以购买年票一次性解锁全部

👉更多活动


别忘了给文章点赞