最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 从原理上大致带你看看vue3更新了哪些常用功能

    正文概述 掘金(付金权同学)   2021-03-07   715

    在这篇博文中, 我们将要聊聊如下几个内容:

    • vite脚手架的原理(对比webpack)
    • vue3在性能上的进一步突破(如: 静态提升, 预字符串化, patch flag等)
    • vue3在组件, API和数据代理上的新变化
    • vue3推出的reactivity apicomposition api

    vite脚手架的原理(对比webpack)

    vite的使用我就不怎么说了, 官网直接手把手教你怎么用

    我们主要来看看vite究竟快在哪里

    打开vite官网我们会发现映入眼帘的第一句话就直接交代了vite的作用:

    vite官方说vite能够给开发者带来更加好的开发体验, 聊到这儿, 我们得想想, 我们使用vue-cli的时候, 开发体验就很差吗? 这里因为看博文的每个同学所接触到项目和团队规模不一致, 我相信有的同学可能能够直接肯定的回答yes, 有的还有疑惑, 没事, 我们来看看webpack他的一个运作原理之后我们在聊聊使用vue-cli可能会出现影响开发体验的点

    webpack的编译原理

    其实说高大上一点是编译原理, 但是事实上我们要聊得就是使用vue-cli搭建的工程当你敲下yarn start / dev命令去要求开启localhost:8000开发服务器的这个过程中都发生了什么

    从原理上大致带你看看vue3更新了哪些常用功能

    根据上图, 我们可以能够基本窥探到webpack他在开启开发服务器时候的基本流程, 那么我们来总结一下步骤:

    1. webpack根据入口模块找寻所有的依赖并进行打包(这个打包过程还蛮繁琐的, 我画了一张图大家可以看一下)

    从原理上大致带你看看vue3更新了哪些常用功能

    1. 走完上面的编译过程以后, webpack会去走一个生成chunk的流程, 然后还会去走合并chunk和输出目录的流程, 这些细节都非常繁琐, 这里就不多作赘述了, 这一步和上一步我们称之为打包
    2. 当走完打包步骤以后, webpack才会利用webpack-dev-server插件来帮助我们开启localhost:8080端口, 这个时候我们就可以访问开发服务器了
    3. 在开发过程中, 如果有文件产生了变化, webpack会直接重新收集该文件所依赖的所有依赖并重新走打包流程

    那么webpack这样做有什么好处呢?

    这样做又有什么坏处呢?

    vite的编译原理

    vite的快就是快在编译上, 话不多说, 我们直接来看看vite的编译原理

    从原理上大致带你看看vue3更新了哪些常用功能

    步骤总结:

    1. 当我们在terminal敲下yarn dev / start的时候, vite无需等待(其实也需要, 但是他的等待是一个做缓存的过程), 直接开启localhost:8080服务器环境, 开发者可以直接访问
    2. webpack是将所有的module打包成一个js然后引入index.html, 而vite直接开启localhost并打开index.html, 但是我们会发现但凡你使用vite构建的工程, index.html在一开始就被引入了main.js, 这样意味着index.html一旦打开浏览器就会再次去请求main.js
    3. 当发现main.js依赖了其他的文件, 比如App.vue, 浏览器又会再次向开发服务器请求App.vue, 这个时候开发服务器会将App.vue编译成JS给到浏览器, 如此反复, 有依赖就请求, 没依赖到的模块鸟都不鸟你
    4. 当需要热替换的时候, vite只会让浏览器重新请求被更改的文件, 而不是所有依赖的文件全部重新打包

    这样做好在哪里?

    这样做有什么缺陷?

    • 一旦你是不支持es6module的老版本浏览器, 那么你将永远只能引入最基础的main.js, 不支持浏览器模块化的话他根本不认识import是什么东西
    • 你将不能使用其他模块化规范的代码, 因为同理, 浏览器只认识es6 module, require是啥他都不知道

    但是这两个缺陷致不致命? 不致命, 首先你作为开发者你肯定是用最新版本的浏览器进行开发, 其次我上面也聊过了, 企业压根就不允许你精神分裂一下这个规范一下那个规范的, 所以这两个问题都不是很致命, 但是vite对于构建速度的提升是非常大的, 特别是项目越大他越明显

    可能有的同学会说, 那既然是考虑到import一个模块就会发送一个请求, 那比如有的node_modules中的模块依赖了特别多的模块不是要发几千上百个请求? 还有的node_modules中的模块是commonjs导出的又怎么办?vite在内部其实也用到了webpack来处理这些问题, 你可以去看看官网的依赖预构建章节

    vite的功能还不远止于此, 如果有兴趣的同学可以去vite官网看看

    vue3在性能上的进一步突破(如: 静态提升, 预字符串化, patch flag等)

    每一次新版本的发布, vue总是再给我们带来新的惊喜, 在vue3中, 尤雨溪又将性能考虑到了极致, 具他在b站分享的时候说: vue3的客户端渲染效率较vue2提升了1.3-2倍, ssr的渲染效率提升了2-3倍

    静态提升和预字符串化

    我们知道哈, 最终不管你在模板里写的是什么, 都会被vue编译成render函数去进行渲染, 而这些性能优化多数都是在render函数中做的文章

    静态节点提升

    首先什么是静态节点, 静态节点必须满足以下两个条件

    1. 必须是vue元素节点
    2. 元素节点上不能动态绑定状态和属性
    <div>i am a static node</div> // 静态节点
    <div class="wrapper">{{ info }}</div> // 动态节点
    <div :class="{
      'diabled': isDisable
    }">hello</div> // 这也是动态节点
    

    那么什么叫做静态节点提升呢?

    // Test.vue
    // vue3支持多根节点, 这个我们后续会说原理
    <template>
      <div>i am static node</div>
      <div>{{ infos }}</div>
    </template>
    
    <script>
    export default {
      data: () => ({
        infos: "i am dynamics node"
      })
    }
    </script>
    

    我们可以打开浏览器, 查看network, 我们之前有说过, 使用vite后会有一个按需加载的机制, 所以我们可以在network中看到整个vite给到我们的组件文件, 我们可以看到给到我们的文件是已经经过编译的, 而使用到的编译工具是@vue/compiler-sfc, 有兴趣的同学可以去了解一下, 我就不做多赘述了

    上面的代码最终会被vue编译成如下形式:

    // 我们会看到第一个静态节点的div, 并不是在render函数内部去创建的
    // 而是在外部创建的, 这样也意味着, render函数中永远使用到的都是这
    // 同样一个引用, 这就是静态节点的提升
    // 其他的代码我们不用看, 只用看这一行就能够知道静态节点提升的含义了
    const _hoisted_1 = createVNode("div", null, "i am static node", -1)
    
    function render(_ctx, _cache, $props, $setup, $data, $options) {
      return (openBlock(),createBlock(_Fragment, null, [
        _hoisted_1,
        _createVNode("div", null, _toDisplayString(_ctx.infos), 1)
      ], 64))
    }
    
    

    静态属性提升

    上面我们说到了静态节点, 那么什么是静态属性呢?

    无非就是没有动态绑定属性值的属性呗

    // class是静态属性 disable是动态属性
    <div class="wrapper"></div> 
    <div :disable="isDisable"></div>
    

    跟静态节点一样, 静态属性将会被缓存到render函数外部

    假设我们有模板是这样的:

    <template>
      <div class="wrapper">{{ infos }}</div> 
      <div :disable="isDisable"></div>
    </template>
    
    <script>
    export default {
      data: () => ({
        isDisable: false,
        infos: "hello"
      })
    }
    </script>
    

    打开浏览器, 我们会发现上面的代码会被编译成

    // 我们会发现即使第一个div是动态节点, 但是只要他上面有静态属性
    // 则静态属性就会被提升到render函数外部
    const _hoisted_1 = { class: "wrapper" }
    
    function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
      return (_openBlock(), _createBlock(_Fragment, null, [
        _createVNode("div", _hoisted_1, _toDisplayString(_ctx.infos), 1 /* TEXT */),
        _createVNode("div", { disable: _ctx.isDisable }, null, 8 /* PROPS */, ["disable"])
      ], 64 /* STABLE_FRAGMENT */))
    }
    
    

    注意如果你的节点上又有动态节点, 又有静态节点, 那你是跑不掉的, 一定会被放进render函数内部的

    预字符串化

    假设我们的模板是这样

    <template>
      <div class="wrapper"></div> 
      <div class="wrapper"></div> 
      <div class="wrapper"></div> 
      <div class="wrapper"></div> 
      <div class="wrapper"></div>
      <div :disable="isDisable"></div>
    </template>
    
    <script>
    export default {
      data: () => ({
        isDisable: false,
        infos: "hello"
      })
    }
    </script>
    

    被编译后的结果如下:

    // 我们会看到vue直接调用了createStaticNodes方法去生成静态节点, 而
    // 生成的静态节点也不会进入vue的虚拟dom树比对环节
    const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<div class=\"wrapper\"></div><div class=\"wrapper\"></div><div class=\"wrapper\"></div><div class=\"wrapper\"></div><div class=\"wrapper\"></div>", 5)
    
    function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
      return (_openBlock(), _createBlock(_Fragment, null, [
        _hoisted_1,
        _createVNode("div", { disable: _ctx.isDisable }, null, 8 /* PROPS */, ["disable"])
      ], 64 /* STABLE_FRAGMENT */))
    }
    

    我们可以大致理解一下上面的代码vue2和3各自生成的虚拟dom树如下图:

    从原理上大致带你看看vue3更新了哪些常用功能

    如图所示, 当需要进行patch比对的时候, vue2没有动静态节点的区分, 都会进行比对, 而vue3有了静态节点, 静态节点他看都不看, 直接去比对动态节点, 这样怎么看效率都会提高不少

    缓存事件处理函数

    <template>
      <div @click="clickHandler"></div> 
      <div @click="secHandler"></div>
    </template>
    
    <script>
    export default {
      methods: {
        clickHandler() {
          
        },
        secHandler() {
    
        }
      }
    }
    </script>
    

    上面的代码会被编译成如下结果

    function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
      return (_openBlock(), _createBlock(_Fragment, null, [
        _createVNode("div", {
          // 我们会发现_cache作为一个缓存池会被作为参数传递给render函数
          // 当我们首次创建虚拟dom的时候, 会往_cache中缓存我们的事件
          // 后续再进行虚拟dom创建时就不会再重新创建引用了
          onClick: _cache[1] || (_cache[1] = (...args) => ($options.clickHandler && $options.clickHandler(...args)))
        }),
        _createVNode("div", {
          onClick: _cache[2] || (_cache[2] = (...args) => ($options.secHandler && $options.secHandler(...args)))
        })
      ], 64 /* STABLE_FRAGMENT */))
    }
    

    有点写累了, 我打王者荣耀去了, 下周再续更吧~

    patch flag 和 block tree

    loading

    vue3在组件, API和数据代理上的新变化

    loading

    vue3推出的reactivity apicomposition api


    起源地下载网 » 从原理上大致带你看看vue3更新了哪些常用功能

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元