Vue3源码学习(1)–框架设计概览

Vue源码学习

前言

基于大崔哥Github开源mini-vue以及霍春阳大佬的《Vue.js设计和实现》学习Vue3源码,最终实现一个具有happy-path的mini-vue

Vue3框架的设计概览

1、权衡的艺术?

一个框架的实现过程中,各个功能模块之间并不是相互独立的,而是相互关联、相互制约的。因此框架的设计需要全局的把控,以便于后续模块的设计和拆分,而我们作为学习者,在学习框架的时候,也应该从全局的角度对框架的进行学习和认知。

1.1 命令式和声明式的权衡

视图层框架通常分为命令时和声明式,那么什么式命令式、声明式

命令式

命令式最主要的特点:关注过程。例如,我们把下面的这段话翻译成原生代码:

获取 id 为 app 的 div 标签  -------> const eDiv = document.getELementById("#app")

它的文本内容设置为 hello world  -------> eDiv.innerText = "hello world"  

为其绑定点击事件,当点击时弹出提示:ok   -------> eDiv.addEventListen("click",()=>{alert("ok")})

复制代码

命令式的代码本身就是描述“做事情的过程”,更加符合我们的思维逻辑

声明式

声明式最主要的特点:关注结果

上述自然语言在Vue中的实现

<div id="app" @click="()=>{alert("ok")}>
复制代码

我们只看到了实现了这个“结果”,但是“结果”的过程,则是由Vuejs帮我们完成。Vuejs帮我们完成了“命令式”这个过程的封装,暴露给我们用户的是声明式的指令

1.2 性能与可维护性的权衡

声明式代码的性能不低于命令式代码

如果我们把直接修改的性能消耗定义为A,找出差异的性能消耗定义为B,那么有:

  • 命令式代码的更新性能消耗 = A
  • 声明式代码的更新性能小号 = A + B

只有在找出差异的性能消耗为0的时候,声明式和命令式代码的性能消耗相同

声明式代码的可维护性高

采用命令式代码开发的时候,我们需要维护实现目标的整个过程,包括要手动的完成DOM元素的创建、更新、删除等。而声明式展示的仅仅是我们要的结果,看上去更加直观

框架设计者要做的就是:在保持可维护性的同时,让性能损失最小

1.3 虚拟DOM

声明式代码的更新性能消耗 = 找出差异的性能消耗 + 直接修改的性能消耗,我们要做的就是尽可能减少找出差异的性能消耗。所谓的虚拟DOM就是为了最小化找出差异这一步。

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

虚拟DOM innerHtml
纯JavaScript运算 创建JavaScript对象(vnode) 渲染HTML字符串
DOM运算 新建所有的DOM元素 新建所有的DOM元素

innerHTML和虚拟DOM更新页面是的性能

虚拟DOM innerHtml
纯JavaScript运算 创建JavaScript对象(vnode) + Diff 渲染HTML字符串
DOM运算 必要的DOM更新 删除所有旧DOM,新建所有新DOM元素
性能因素 与数据变化量相关(JS层面与运算) 与模板大小相关)(DOM层面运算)

粗略总结:

性能低 ——————->性能高

innerHTML < 虚拟DOM < 原生JavaScript方法

同时还与页面大小、变更部分大小都有关,除此之外,与创建页面更新页面也有关系,权衡之后,选择虚拟DOM

1.4 编译时和运行时

纯运行时

假设我们设计的框架,它提供了一个render函数,用户可以为该函数提供一个树型的数据对象,然后Render函数会根据对象递归的处理数据渲染成DOM元素

function render(obj,root){
    const { tag ,children } = obj
    const el = document.createElement(tag)
    if(typeof children === "string"){
        const text = document.createTextNode(children)
        el.appendChild(text)
    }else if (Array.isArray(children)){
        //递归调用
        children.forEach(child=>{
            render(children,el)
        })  
     }
     
     root.appendChildren(el)
}

const obj ={
    tag:"div",
    children:[
        {tag:"span",children:"helloworld"}
    ]
}

render(obj,document.body)

复制代码

用户在使用render函数渲染内容的时候,必须为render函数提供一个属性的数据结构,这就是一个纯运行时的框架

运行时 + 编译时

如果我们想使用HTML模板,就需要将HTML模板编译成render函数需要的属性结构,就可以继续使用render函数了

为此,编写一个compiler函数

const html = `
    <div>hello world</div>`

const obj = function compiler(html)
render(obj,document.body)
   
复制代码

这是框架就变成了运行时 + 编译时的框架

编译时

直接将html模板编译成命令式代码,不需要render函数,仅仅使用一个compiler函数,这是框架就是编译时框架

Vue.js3 是一个编译时 + 运行时的框架。

2、框架设计的核心要素

  • 提升用户开发体验

  • 控制框架的代码体积

  • 框架良好的Tree-shaking

  • 框架应该输出怎么的构建产物

  • 特性开关

  • 错误处理

  • 良好的TypeScript类型支持

总结

通过《Vue.js设计和实现》来了解框架的设计的理念,具体内容请大家阅读书籍吧

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享