1. Vue3 支持 vue2 的大多数特性;

  2. 更好的支持 Typescript

谈谈对 vite 的理解,最好对比 webpack 说明

  1. webpack 原理图

  2. vite 原理图

  3. 理解:

    1. webpack 会先打包,然后启动开发服务器,请求服务器时直接给予打包结果;而 vite 是直接启动开发服务器,请求哪个模块再对该模块进行实时编译;
    2. 由于现代浏览器本身就支持 ES Module,会自动向依赖的 Module 发出请求,vite 充分利用这一点,将开发环境下的模块文件,就作为浏览器要执行的文件,而不是像 webpack 那样进行打包合并;
    3. 由于 vite 在启动的时候不需要打包,也就意味着不需要分析模块的依赖、不需要编译,因此启动速度非常快;当浏览器请求某个模块时,再根据需要对模块内容进行编译;这种按需动态编译的方式,极大的缩减了编译时间,项目越复杂、模块越多,vite 的优势越明显;
    4. HMR 方面,当改动了一个模块后,仅需让浏览器重新请求该模块即可,不像 webpack 那样需要把该模块的相关依赖模块全部编译一次,效率更高;
    5. 当需要打包到生产环境时,vite 使用传统的 rollup 进行打包,因此,vite 的主要优势在开发阶段;另外,由于 vite 利用的是 ES Module ,因此在代码中不可以使用 CommonJS

效率提升

  1. 客户端渲染效率比 vue2 提升了 1.3~2 倍;

  2. SSR 渲染效率比 vue2 提升了 2~3 倍;

  3. 面试题:vue3 的效率提升主要表现在以下几个方面;

静态提升

  1. 下面的静态节点会被提升

    • 元素节点
    • 没有绑定动态内容
    // vue2 的静态节点
    render(){
        createVNode("h1", null, "Hello World")
        // ...
    }
    
    // vue3 的静态节点
    const hoisted = createVNode("h1", null, "Hello World")
    function render(){
        // 直接使用 hoisted 即可
    }
    
  2. 静态属性会被提升

    html
    JavaScript
    <div class="user">
        {{user.name}}
    </div>
    
    const hoisted = { class: "user" }
    
    function render(){
        createVNode("div", hoisted, user.name)
        // ...
    }
    

预字符串化

  1. 示例代码

    <div class="menu-bar-container">
    <div class="logo">
        <h1>logo</h1>
    </div>
    <ul class="nav">
        <li><a href="">menu</a></li>
        <li><a href="">menu</a></li>
        <li><a href="">menu</a></li>
        <li><a href="">menu</a></li>
        <li><a href="">menu</a></li>
    </ul>
    <div class="user">
        <span>{{ user.name }}</span>
    </div>
    </div>
    
  2. 当编译器遇到大量连续的静态内容,会直接将其编译为一个普通字符串节点

    const _hoisted_2 = _createStaticVNode("<div class=\"logo\"><h1>logo</h1></div><ul class=\"nav\"><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li></ul>")
    
  3. vue2 编译后的虚拟 dom

  4. vue3 编译后的虚拟 dom

缓存事件处理函数

  1. 事件

    <button @click="count++">plus</button>
    
  2. vue2 事件函数的处理

    // vue2
    render(ctx){
        return createVNode("button", {
            // 每次渲染都要重新创建一个事件函数,频繁创建浪费空间
            onClick: function($event){
                ctx.count++;
            }
        })
    }
    
  3. vue3 事件函数的处理

    // vue3
    render(ctx, _cache){
        return createVNode("button", {
            // 事件函数一般不会变化,vue3 将事件函数缓存下来
            onClick: cache[0] || (cache[0] = ($event) => (ctx.count++))
        })
    }
    

Block Tree

  1. 示例代码

    <form>
    <div>
        <label>账号:</label>
        <input v-model="user.loginId" />
    </div>
    <div>
        <label>密码:</label>
        <input v-model="user.loginPwd" />
    </div>
    </form>
    
  2. vue2diff 算法

    • vue2 在对比新旧树的时候,并不知道哪些节点是静态的,哪些是动态的,因此只能一层一层比较,这就浪费了大部分时间在比对静态节点上;
  3. vue3diff 算法

    • Block Tree 是优化的 diff 算法的核心思想;
    • vue3 在对比新旧树的时候,根据 PatchFlag 能判断出哪些是静态节点,哪些是动态节点,然后将动态节点全部放到 form 根节点数组中,每次对比 dom 只需要对比 form 根节点数组中的虚拟节点,不需要对比静态节点,效率大大提升;

PatchFlag

  1. 示例代码

    <div class="user" data-id="1" title="user name">
        {{user.name}}
    </div>
    
  2. vue2 在对比每一个节点时,并不知道这个节点哪些相关信息会发生变化,因此只能将所有信息依次比对;

  3. vue3 编译器会记录 节点动态 的部分,利用 PatchFlag 进行标记,对比节点的时候,只需要对比 变化 的部分,也就是被 PatchFlag 标记的部分;

面试题

为什么 vue3 中去掉了 vue 构造函数?

vue2 的全局构造函数带来了诸多问题:

  1. 调用构造函数的静态方法会对所有 vue 应用生效,不利于隔离不同应用;
  2. vue2 的构造函数集成了太多功能 ($el、$set、$mount、$delete、$data…) ,不利于 tree shakingvue3 把这些功能使用普通函数导出,能够充分利用 tree shaking 优化打包体积;
  3. vue2 没有把组件实例和 vue 应用两个概念区分开,在 vue2 中,通过 new Vue 创建的对象,既是一个 vue 应用 ,同时又是一个特殊的 vue组件vue3 把两个概念区别开来,通过 createApp 创建的对象,是一个 vue 应用 ,它内部提供的方法是针对整个应用的,而不再是一个特殊的组件;

谈谈你对 vue3 数据响应式的理解

  1. vue3 不再使用 Object.defineProperty 的方式定义完成数据响应式,而是使用 Proxy

  2. 除了 Proxy 本身效率比 Object.defineProperty 更高之外,由于不必递归遍历所有属性,而是直接得到一个 Proxy;所以在 vue3 中,对数据的访问是动态的,当访问某个属性的时候,再动态的获取和设置,这就极大的提升了在组件初始阶段的效率;

  3. 同时,由于 Proxy 可以监控到数组成员的新增和删除,因此,在 vue3 中新增成员、删除成员、索引访问等均可以触发重新渲染,而这些在 vue2 中是难以做到的;

Composition API 和 Options API 有何不同?

  1. Composition API 是一组 APl,包括:Reactivity APl、生命周期钩子、依赖注入,使用户可以通过导入函数方式编写 vue 组件,而 0ptions API 则通过声明组件选项的对象形式编写组件;

  2. Composition API 最主要作用是能够简洁、高效复用逻辑,解决了过去 Options API 中 mixins 的各种缺点;

    • 另外 Composition API 具有更加敏捷的代码组织能力,很多用户喜欢 0ptions API,认为所有东西都有固定位置的选项放置代码,但是单个组件增长过大之后这反而成为限制,一个逻辑关注点分散在组件各处,形成代码碎片,维护时需要反复横跳,composition API 则可以将它们有效组织在一起;
    • 最后 Composition API 拥有更好的类型推断,对 ts 支持更友好,options API 在设计之初并未考虑类型推断因素,虽然官方为此做了很多复杂的类型体操,确保用户可以在使用 Options API、时获得类型推断,然而还是没办法用在 mixins 和 provide/inject 上;
  3. Vue3 首推 Composition API,但是这会让我们在代码组织上多花点心思,因此在选择上,如果项目属于中低复杂度的场景,0ptions API 仍是一个好选择,对于那些大型,高扩展,强维护的项目上,Composition API 会获得更大收益;

打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 谈谈对 vite 的理解,最好对比 webpack 说明
  2. 2. 效率提升
    1. 2.1. 静态提升
    2. 2.2. 预字符串化
    3. 2.3. 缓存事件处理函数
    4. 2.4. Block Tree
    5. 2.5. PatchFlag
  3. 3. 面试题
    1. 3.1. 为什么 vue3 中去掉了 vue 构造函数?
    2. 3.2. 谈谈你对 vue3 数据响应式的理解
    3. 3.3. Composition API 和 Options API 有何不同?