框架的选择(运行时&编译时)

运行时与编译时

在设计一个框架的时候,我们有三个选择:纯运行时运行时+编译时纯编译时。所以我们需要很准确的了解到这三个不同选择的概念以及作用。

1.运行时

我们首先了解一下传纯运行时的框架。
假设我们创建了一个开个你家,它提供了一个 Render 函数,用户只需要给这个函数传递一个树形结构的对象,然后 Render 函数会根据这个对象递归地将数据渲染成 DOM 元素

树形结构数据如下:

const obj = {
  tag: "div",
  children: [{ tag: "span", children: "hello coder_MX" }],
};

Render 函数如下

function Render(obj, root) {
  const el = document.createElement(obj.tag);
  if (typeof obj.children === "string") {
    const text = document.createTextNode(obj.children);
    el.appendChild(text);
  } else if (obj.children) {
    // 数组,递归调用 Render,使用 el 作为 root 参数
    obj.children.forEach((child) => Render(child, el));
  }

  // 将元素添加到 root
  root.appendChild(el);
}

运行时执行

const obj = {
  tag: "div",
  children: [{ tag: "span", children: "hello coder_MX" }],
};
// 渲染到 body 下
Render(obj, document.body);

在浏览器控制台执行上述代码,就能直接看到我们预期的内容了

结论(纯运行时)

到现在,你应该已经大致明白了何为纯运行时了,就是用户在使用渲染页面的时候,直接给 Render 函数传的就是树形结构的 DOM 元素对象,其他无需要做任何事情。

那么,用户手写树形结构对象真的是一件简单的事情吗?于是我们引出了编译时+运行时的概念

2.编译时+运行时

接着上面运行时的问题讨论,一个框架的存在,不仅仅是为了降低渲染的消耗,更重要的是要降低开发者的心智负担,这样用才是符合用户的框架,接下来我们详细讨论一下编译时

为了满足用户的需求,我们要想到能不能引入编译的手段,可以直接把 HTML 标签编译成树型结构的数据对象,这样用户便编写的 HTML 也可以使用 Render 函数进行渲染啦!

用户编写的 HTML 代码

    <div>
        <span>hello coder_M</span>
    </div>

经过编译处理,我们得到如下的树形结构对象

const obj = {
  tag: "div",
  children: [{ tag: "span", children: "hello coder_MX" }],
};

再接下来,Render 函数就可以直接享用上述的结构数据了

所以为了完成上述的逻辑,我们需要开发一个compiler的程序,它的作用就是将 HTML 代码编译成树形结构的对象。如下:

const html = `
 <div>
 <span>hello coder_MX</span>
 </div>
 `;
// 调用 Compiler 编译得到树型结构的数据对象
const obj = Compiler(html);
// 再调用 Render 进行渲染
Render(obj, document.body);

结论(运行时+编译时)

上述代码的顺利执行,这时候,我们的框架就变成了一个 运行时+编译时的框架。它既支持运行时(用户直接使用树形结构的对象进行渲染),又支持编译时(将用户编写的 HTML 代码编译成树形结构数据,传递给 Render 函数)。
但是更准确的讲,上述代码属于运行时编译,意思时,代码运行的时候才进行了编译处理,而这样一定会产生一些性能的开销,因此我们可以在构建的时候就执行Compiler,当用户需要渲染 DOM 的时候,就无需编译了,这对性能来说时非常友好的。

3.纯编译时

屏幕面前的你一定会想到,既然Compiler程序可以将 HTML 代码编译成声明式框架需要的树形结构 DOM,那为什么不直接编译成命令式的代码呢?当然可以,如下

<div>
  <span>hello coder_MX</span>
</div>

经过Compiler程序编译,得到如下代码:

    const div = document.creatElement('div')
    const span = document.creatElement('span')
    span.innerText = 'hello coder_MX'
    div.appendChild(sapn)
    document.body.appednChild(div)

结论(纯编译时)

这样,我们仅仅需要一个 Compiler函数就可以了,根本无需Render函数,我们就得到了一个纯编译时的框架了,因为我们不支持任何运行时内容,只有用户进行了编译,我们就能立马渲染。

全文总结

纯运行时框架:由于它没有编译的过程,因此我们没办法分析用户提供的内容。
运行时+编译时:可以分析用户提供的内容,看看哪些内容未来可能会改变,哪些内容永远不会改变,这样我们就可以在编译的时候提取这些信息,然后将其传递给 Render 函数,Render 函数得到这些信息之后,就可以做进一步的优化
纯编译时:也可以分析用户提供的内容。由于不需要任何运行时,而是直接编译成可执行的 JavaScript 代码,因此性能可能会更好,但是这种做法有损灵活性,即用户提供的内容必须编译后才能用

##拓展
运行时+编译时的框架: Vue、Angular
纯编译时Svelte(真实性能可能达不到理论高度)


感谢阅读~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值