纯运行时
假设框架提供一个 Render 函数,用户为函数提供一个树形结构的数据对象,Render 函数会根据该对象递归地将数据渲染成 DOM 元素。
规定对象有两个属性:tag 代表标签名称, children 既可以是一个数组(代表字节点),也可以是字符串(代表文本子节点)
1 | const obj = { |
用户在使用 Render 函数渲染内容时,直接为其提供一个树形结构数据对象,运行后便会渲染对应的 DOM 元素。这就是一个纯运行时的框架实现。
运行时 + 编译时
手写树形结构的数据对象太麻烦,且不直观,希望用类似于 HTML 标签的方式描述树形结构的数据对象。
为满足需求,需要引入编译的手段,把 HTML 标签编译成树形结构的数据对象,就可以继续使用 Render 函数了。
编写一个 Compiler 程序,它的作用就是把 HTML 字符串编译成树形结构的数据对象。用户使用时分别调用 Compiler 函数和 Render 函数:
1 | const html = ` |
上面的实现就是一个运行时 + 编译时的框架。既支持运行时,用户直接提供树形结构的对象;也支持编译时,用户提供 HTML 字符串。
准确的说,上面代码其实是运行时编译,代码运行的时候才开始编译。
可以在构建的时候就执行 Compiler 将用户提供的内容编译好,优化性能。
纯编译时
既然编译器可以把 HTML 字符串编译成数据对象,能不能直接编译成命令式代码?
这样只需要一个 Compiler 函数就可以了,变成一个纯编译时的框架,不支持任何运行时的内容,用户代码要通过编译器编译后才能运行。
总结
上面用简单的例子理解了框架设计层面的运行时、运行时 + 编译时以及编译时。
纯运行时的框架,由于没有编译的过程,无法分析用户提供的内容;
如果加入编译步骤,可以分析用户提供的内容,将分析得出的信息传递给 Render 函数,Render 函数就可以做进一步优化了;
纯编译时的框架,也可以分析用户提供的内容,由于不需要任何运行时,直接编译成可执行的 JavaScript 代码,性能可能会更好,但是灵活性不好,用户提供的内容必须编译后才能使用。
Vue.js3 保持了运行时 + 编译时的架构,在保持灵活性的基础上尽可能优化。