Skip to content

第1章-权衡的艺术

1.1 命令式和声明式

从范式上来看,视图层框架通常分为命令式和声明式,它们各有优缺点

  • 命令式

    例子:

    js
    const div = document.querySelector('#app') // 获取 div
    div.innerText = 'hello world' // 设置文本内容
    div.addEventListener('click', () => { alert('ok') })
    const div = document.querySelector('#app') // 获取 div
    div.innerText = 'hello world' // 设置文本内容
    div.addEventListener('click', () => { alert('ok') })

    可以看到,自然语言描述能够与代码产生一一对应的关系,代码本身描述的是“做事的过程”,这符合我们的逻辑直觉。

  • 声明式

    例子:

    js
    <div @click="() => alert('ok')">hello world</div>
    <div @click="() => alert('ok')">hello world</div>

    可以看到,我们提供的是一个“结果”,至于如何实现这个“结果”,我们并不关心。所以它是一个声明式的代码。

1.2 性能与可维护性的权衡

结论:声明式代码的性能不优于命令式代码的性能。

声明式代码的更新性能消耗 = 找出差异的性能消耗 + 直接修改的性能消耗

js
div.textContent = 'hello vue3' // 直接修改
div.textContent = 'hello vue3' // 直接修改

VS

html
<!-- 之前: -->
<div @click="() => alert('ok')">hello world</div>
<!-- 之后: -->
<div @click="() => alert('ok')">hello vue3</div>
<!-- 之前: -->
<div @click="() => alert('ok')">hello world</div>
<!-- 之后: -->
<div @click="() => alert('ok')">hello vue3</div>

可以发现直接修改textContent的性能肯定是优于声明式的。因为声明式框架还要经过框架运行时的过程。

1.3 虚拟 DOM 的性能到底如何

在大部分情况下,我们很难写出绝对优化的命令式代码,尤其是当应用程序的规模很大的时候,即使你写出了极致优化的代码,也一定耗费了巨大的精力,这时的投入产出比其实并不高。

innerHTML 和虚拟 DOM 在创建页面时的性能

20220907193611

1.4 运行时和编译时

  • 纯运行时

    不需要任何编译,直接运行代码,就是运行时。比如你使用react,但不使用jsx语法,直接手写React.createElement,这就少了编译的步骤,可以直接运行代码。

  • 纯编译时

    需要对代码编译后,才能运行,就是编译时。例如Svelte框架, 你需要按照Svelte提供的dsl语法来写代码,经过编译后才运行。

  • 运行时编译

    代码在运行的时候编译,然后执行。例如我们用vue打包后的代码vue.global.js。这个文件中就包含了compileTemplate的代码。我们执行代码的过程中,还要经过编译,最后执行。

  • 编译时 + 运行时

    需要先经过打包工具对你的代码进行编译。然后在运行的时候就不需要编译了,直接执行。例如vue-loader,在项目冷启动或hmr的时候进行编译。