前端框架的运行时与编译时

前端框架的运行时与编译时

本文写于 2022 年 5 月 20 日。

运行时与编译时是前端工程师常常听到的两个词。

比如 Vue 运行时、Angular 运行时、React 运行时……

又比如 svelte 框架,总听到他的宣传说的是“0 运行时”,所以他的工作其实就是在“编译时”了。

这两个词到底是什么意思呢?

虚拟 DOM 的渲染

我们以虚拟 DOM 为例来讲解运行时与编译时。

虚拟 DOM 是 React/Vue 都采用了的一种设计手段,简单来讲它就是将 HTML 的 DOM,用一套 JS 对象来表示。

<div id="app">
  <h1>Hello World</h1>
</div>

可以简单的这么表示:

const vDom = {
  tag: "div",
  id: "app",
  children: [
    {
      tag: "h1",
      children: ["Hello World"],
    },
  ],
};

那么我们如何渲染这个对象呢?

可以提供一个 render 函数来做到。

function render(vDom, container) {
  const el = document.createElement(vDom.tag);
  el.id = vDom.id;
  if (!vDom.children || vDom.children.length === 0) {
    container.append(el);
    return;
  }

  for (let i = 0; i < vDom.children.length; i++) render(vDom[i], el);
}

我们去遍历这个对象和他的 children 属性以渲染 DOM。(这个写法效率很低,只做示例用)

这就叫做运行时。

我们在代码跑起来之后,才进行的 DOM 渲染。

虚拟 DOM 写起来太麻烦怎么办

接下来问题来了,虚拟 DOM 实在是太难写了。我们这么去写 UI 会写到吐血的。

能不能让我们写普通的 HTML,然后把它变成虚拟 DOM 呢?

当然可以,我们的 Vue 和 React 都提供了这样的工具,所以我们才能愉快的书写 Vue template 和 JSX。

假设这是一个函数名叫 complier

const vDom = complier(htmlStr);
render(vDom, document.querySelector("#app"));

这样我们就能衔接上之前写的 render 方法。

直到此时,我们依旧是纯运行时框架。但 complier 函数并没有必要放到运行时呀!

我们可以写一个脚本把 complier 的结果直接硬编码到输出文件中。

// 源文件
<template>
  <div>
    <!-- ... -->
  </div>
</template>

<script>
// do something here...
</script>
// 输出文件
const vDom = {
  tag: "div",
  children: [
    // ...
  ],
};
render(vDom, app);

在浏览器中我们无须源文件,只需要输出文件,就可以运行我们的 render 函数了。

render 函数也能编译?

既然我们可以把 jsx/Vue template 编译成 vDom,那我们能不能直接把 render 函数也给干掉呢?

要知道 render 现在需要进行递归操作,效率是比较差的。

我们要时能把所有的递归操作都干掉,直接编译成一连串的 DOM 操作,岂不美哉?

没错,这样做是可以的。

如果我们把源代码直接编译成一连串的 DOM 操作,那么我们做的就叫做 “纯编译时”框架。因为在代码运行过程中,我们的框架没有做任何操作。

(完)

posted @ 2022-06-06 19:40  徐航宇  阅读(963)  评论(0编辑  收藏  举报