01-权衡的艺术

46 阅读4分钟

权衡的艺术

引入

设计框架要从全局考虑权衡

比如框架应该设计成命令式还是声明式,纯运行还是纯编译还是运行时+编译时

命令式和声明式

命令式

特点:关注过程

用自然语言描述能够与代码产生一一对应的关系

例子:自然语言描述转化为代码

 //获取id为app的div标签
 //他的文本内容是hello world
 //为其绑定点击事件
 //点击时弹出提示OK

代码:

 const div = document.querySelector('#app')
 div.innerText = 'hello world'
 div.addEventlistener('click', () => {alert('OK')})

声明式

特点:关注结果

用vue实现上述代码:

 <div @click="() => {alert('OK')}">hello world</div>

可以知道,vue.js帮我们封装了过程,内部是命令式,暴露给用户的更加声明式

性能和可维护性

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

例子:对上面的代码中的文本内容改成hello vue3

  • 命令式的操作:

     div.textContent = 'hello vue3'
    
  • 声明式的操作:

     <div @click="() => {alert('OK')}">hello vue3</div>
    

对比上述代码可以知道,对于声明式来说,框架需要先找到差异再只更新变化的地方

所以声明式要比命令式消耗多一部分查找差异时候的性能

但是vue在权衡两者的性能时,还是选择了声明式,因为其代码好维护,省去了手动创建元素等操作

虚拟DOM的性能如何

这里主要比较innerHTML与虚拟DOM性能

创建页面时性能

  • innerHTML创建页面的性能:HTML字符串拼接的计算量 + innerHTML的DOM计算量
  • 虚拟DOM创建页面的性能:创建JS对象的计算量 + 创建真实DOM的计算量

在创建页面的性能比较上,两者性能上并没有很大的区别,虚拟DOM也没有优势

更新页面时性能

  • innerHTML更新页面的过程:

    重新构建HTML字符串,在重新设置DOM元素的innerHTML属性

    也就是说,哪怕只改了一个字,都要重新设置innerHTML属性

    重新设置innerHTML也就意味着销毁所有的旧的DOM元素,再全量创建新的DOM元素

    性能公式:渲染HTML字符串 + 销毁所有旧DOM + 新建所有新DOM

    性能因素:与模板的大小有关

  • 虚拟DOM更新页面:

    重新创建新的JS对象(虚拟DOM树),再比较新旧虚拟DOM树,找到变化并更新

    性能公式:创建新的JS对象 + Diff + 必要的DOM更新

    性能因素:与数据变化量有关

在更新页面的性能比较上,虚拟DOM总体来说要比innerHTML更加优秀

与原生比较

原生JS:由于是手动创建删除修改DOM元素,所以他的性能是最高的,但是可维护性差

虚拟DOM:性能不错,可维护性强

innerHTML:性能差,可维护性中等

运行时和编译时

运行时

用户直接输入指定的数据结构数据,去直接运行

比如生成一棵树,用户需要输入指定的树形结构,再使用一个递归函数去生成树

运行时+编译时

按照上面的例子,用户可以传入HTML字符串去生成树

过程也就是先将HTML转化成树形数据结构,再将该数据结构转化成树

这种方式既支持运行时,即用户直接传入数据对象生成树,又支持编译时,用户直接传入HTML字符串,将其编译为数据对象再交给运行时处理

编译时

直接将HTML转化为命令式代码,但是需要放入编译器编译运行

三者比较

  • 运行时框架:没有办法分析用户提供的内容
  • 编译时+运行时:可以分析用户提供的内容,提取有用信息
  • 编译时框架:直接编译成可执行的JS代码,性能可能会更好,但是有损灵活性,即用户的内容必须编译后才能用

Vue3采用了运行时+编译时架构,在保持灵活性的基础上尽可能去优化