在 Rtos 上的动态渲染思考
前言
这里讨论的动态渲染是指,如 React、Vue 等框架一样,通过提前声明DSL(JSX, Vue模板语法)描述数据与页面节点之间的关系,然后再改变数据字段、数据结构,框架层面自动把数据变化映射成 UI 变化的过程。
为什么要研究这个?
我所在的业务是菜鸟 IoT,IoT设备通常针对某一特殊场景,只提供刚刚好够用的硬件性能和硬件模块(这有助于控制客户成本)。比如扫码枪(PDA)是由一个扫码头 + 一块240x320的屏幕,全部操作由6个实体按键完成,运行时内存以KB计算、闪存不过64M。可别指望在这样的设备上运行一个现代浏览器。除了低端设备也有基于安卓打造的移动工作台,具备和一般手机相当的性能,前端 UI 研发体系可以基于浏览器直接怼上去。如何在低端、高端设备上保持 UI 研发的一致性,最好是能在低端设备上也能直接复用现有的研发体系(构建、发布、语法)。并且这样的适配需要跟上社区的技术发展。
浏览器里的动态渲染
无论上层框架如何变化,浏览器提供的操作DOM 的API无非,appendChild、insertBefore 、 removeChild 。知道底层逻辑后,假如我们要在非浏览器环境下运行这些上层框架、或把这些上层框架嫁接到其他 IoT 设备中去。我们只需要实现一些3个底层必要的API即可。
把 preact运行 nodejs 中验证想法
- Node.js
export default class Node {
constructor(tagName){
console.log("new Node");
this.tagName = tagName;
this.nodeType = 1;
}
setAttribute(key, val){
console.log("setAttribute", key, val);
}
appendChild(node){
node.parentNode = this;
console.log("appendChild", this.tagName);
}
removeChild(){
console.log("removeChild", this.tagName);
}
addEventListener(){
console.log("addEventListener", arguments);
}
}
document.js
import Node from './Node.js';
class Document extends Node {
constructor(){
super();
this.body = this.createElement('body');
this.parentElement = new Node("HTML");
this.documentElement = this.parentElement;
this.ownerDocument = this.parentElement;
this.nodeType = 9;
}
createElement(tagName){
const node = new Node(tagName);
node.ownerDocument = this;
return node;
}
createTextNode(){
return new Node("text")
}
createEvent(){
return {}
}
removeChild(){
console.log("removeChild");
}
}
export default new Document();
- index.js
import document from './browser/Document.js';
import { h, Component, render, useEffect, useState } from './preact/index.js';
function App(){
const [r, setR] = useState(0);
useEffect(function(){
setInterval(() => {
setR(Math.round(Math.random() * 10))
}, 1000);
}, []);
console.log("r", r);
return h("div", null, [
r % 2 === 0 ? h("p", null, [r]) : null
])
}
render(h(App), document.body);
上面的代码使得 preact 可以直接运行在 nodejs 环境中,我们只需要提前在环境中注入 document 对象的必要几个方法即可。(笔者也尝试把 react 运行在 nodejs 中也可以成功,不过 react-dom 依赖的浏览器 API 要远多余于 preact)。
Rtos 系统上的动态渲染
基于浏览器里的动态渲染思考,我们只需要在 Rtos 系统中提供 4 个标准的 DOM 操作API ,preact 就可以直接运行。这样可以把Rtos 上的 UI 研发直接与现代浏览器保持一致。并且复用已有的代码构建、模块组织能力。不过因为硬件的局限性,必须要限制基础标签的范围(比如不能使用input, iframe 等标签,当前这些标签在这个设备所工作的场景中基本也用不到)。
硬件评估
- jerryscript:64kb
- preact:15KB
- 浏览器 API 模拟:5KB 以内
- 单页面:10KB
- 组件库:50KB