首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >通用底层DOM/BOM平台

通用底层DOM/BOM平台

作者头像
否子戈
发布2021-07-16 11:28:34
8900
发布2021-07-16 11:28:34
举报
文章被收录于专栏:

粉丝过1000啦,没想到自己小小一个公众号,还有这么多朋友关注,再次感谢你的厚爱~~以后多写文章回馈~~


最近这两天一直在想一种实现方式。我们现在的前端应用,实现上基于DOM是最好的最流行的,不过,大部分前端都构建了自己的路由系统,这又依赖BOM。也就是说,目前大部分前端应用,都是基于DOM+BOM实现的。那么,我是否可以创建一个通用的DOM/BOM平台,让这些应用跑在这个平台上。

让前端应用跑在一个DOM/BOM平台上,听上去有点莫名其妙,为啥不跑在浏览器里面?没错,我就是想脱离浏览器跑这些应用。比如在nodejs里面跑(目前有JSDOM可以支持这个效果),虽然没有界面可以看,但是可以用来做一些单元测试的工作。比如在webworker中跑,众所周知,webworker是没有DOM API的,假如有了这个平台,那么就可以在worker中跑一个vue应用(虽然没有界面)。同样的道理,能否更远一点,跑在非js的环境中,比如flutter(目前阿里开源的Kraken支持这个效果)甚至C++写的原生应用中。想一想,在一个树莓派中跑一个vue应用。于是,我想出了这样一个架构:

由于从某些角度讲,DOM是BOM的一部分,所以,上图中我用VBOM包含了BOM和DOM的API。其中,VBOM这一层和Driver framework这一层是整个架构要实现的核心。VBOM是用纯js实现的DOM+BOM环境,只要把已有的vue代码,包在一个VBOM实例的闭包里面(用babel把全局变量的引用切换到window上),那么vue代码所做的任何关于DOM/BOM的操作,都是在这个VBOM的实例内部完成。Driver framework则是监听/操作这个VBOM实例,对接不同的平台,比如小程序,由于小程序是js写的,所以,引用js-driver,然后在driver的各个生命周期钩子函数上写小程序要做的事情,driver会把VBOM中有关DOM/BOM的变化告诉给小程序,也会把来自小程序的消息发送给VBOM产生新的副作用。而flutter上,我们可以使用dart-driver,原生应用可以使用cpp-driver,python-driver, rust-driver, java-driver等等,通过driver之后,终端代码里面只写终端语言代码,不需要写任何js相关的东西。而回过来,应用这端,开发者只需要写vue或react,不需要考虑自己的应用会在哪个环境里面去跑。

再用一个基于webworker的微前端方案的例子说明:

微前端要解决的是一个沙箱问题,比如一个vue应用,要在宿主应用中加载运行,那么,这个vue应用里面可能操作DOM, location, history等等,这些东西会导致vue这个子应用和宿主应用去抢location, history进行操作。我在mfy中的做法是创建一个iframe,然后把里面的window, location, history借过来给子应用去操作,通过监听,同步子应用和父应用的相关信息,这样就不会出现抢的局面。但是,由于浏览器环境中的特殊原因,目前所有的微前端方案,实现沙箱都需要借助Function来实现,同时还需要用with这个性能极差的语法(而且这个语法已经被抛弃了)来解决全局变量修改问题(虽然也可以用babel进行编译处理来去掉with语法)。这些方案都无法避免父子应用的某些冲突,特别是子应用代码运行过程中发现当前提供的资源不符合自己代码实现的逻辑,报错。

既然浏览器环境下沙箱问题这么多,性能这么差,那么我能不能把沙箱迁移到一个webworker中,在worker环境下,一个子应用一个worker,根本不存在抢资源问题,也不需要用Function来包裹vue代码。但是,worker中没有DOM啊,也没有location, history,所以就想到了,我们需要自己造一套DOM/BOM的环境,然后把这套环境放在webworker中,这样可以让vue应用在worker中跑起来,vue操作的,是VBOM,虽然不会报错,但是没有任何界面效果。

所以,接下来,就需要driver出场,driver监听VBOM中的变化,把这些变化交给controller(controller是微前端框架基于js-driver实现的一个运行在webworker中的控制器),controller通过postMessage发送给主线程,由主线程的renderer收到message之后决定怎么修改DOM。当用户点击子应用区域内的某个按钮之后,renderer将该点击事件postMessage给controller,由controller分析并把对应的DOM事件发送给driver,driver要知道这个事件发生在哪个DOM节点上,于是在VBOM中对应的节点上触发该事件,VBOM实际上是vue的运行环境,vue组件上的事件被触发,回调函数被执行,引发VBOM中新的DOM更新,再次走一遍前面的过程。

看上去好绕啊!!!但是,你要知道,其中,对于框架开发者而言,他们维护的是微前端框架,对于宿主开发者而言,他们维护的是微前端框架的配置,对于子应用开发者而言,他们维护的是vue这个应用。真正需要经常调整、修改的,是vue应用这一层,其他两者基本上是以逸待劳,一劳永逸。所以,一旦这一套跑起来之后,不管是vue也好,react也好,开发者只需要了解自己熟悉的基于DOM/BOM的web开发即可,不需要关心自己是在什么环境下运行。这对小程序的开发者而言,肯定深有感触,小程序开发因为有线程约束,导致开发者有的时候非常痛苦,翻遍开发文档都找不到问题的根源。而如果有了上面这一套方案,开发者只需要考虑在自己熟悉的web平台上开发即可,而不需要考虑其他。

补充一点,如果需要调用原生的能力,需要框架开发者在driver那一层,向VBOM提供某些接口的能力,比如提供调用摄像头的能力,比如提供app是否被切换到后台运行的事件等等(很多hybird的惯用手法)。对于应用的开发者而言,无非是增加了一些特殊接口和事件,仍然还是DOM/BOM那一套。

本文发表在博客上后,有小伙伴留言,看完还是没有明白。我觉得继续补充只会让你更糊涂,但是我还是再说下我的看法。对react有思考的同学,会认为react实质上UI的DSL,因为它提供了自定义render的能力(vue3也开放了这个能力),所以,基于该DSL,到底要render成什么结果,由开发者自己来决定。

回到本文,我认为DOM是比react更高级的DSL,它是一个w3c标准的DSL,你有非常明确的标准作为依据,每一个操作会产生什么影响都有标准告诉你,因此,是更加完美的描述体系。只不过现在的DOM是由浏览器实现的,浏览器提供DOM接口,获得DOM实例后,用来渲染界面(或者说按照HTML5标准渲染界面)是它的实现方式,我想的是,DOM的接口是标准的,那么我们也可以有其他的实现,获得DOM实例之后,也可以不走HTML5的标准实现,而是用来做其他描述,这个过程和react/vue自定义渲染器一样,我们把DOM/BOM作为DSL,为它们编写自定义渲染器,用来完成非浏览器方式的副作用。

我找了很久,没有找到纯js实现的DOM/BOM,目前有一些项目中有一些实现,例如kbone、kraken(flutter实现)、worker-dom等项目中,但是我看它们基本上都和自己的逻辑绑定了,而非纯粹的用js实现标准接口(或者说没有脱离具体的目标,实现任意的扩展能力)。如果你有发现用纯js实现的DOM/BOM,请在下方评论区,或者直接在公众号中告知我,不甚感激~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 唐霜 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档