Vue3有了解过吗?能说说跟Vue2的区别吗?Vue3性能优化的地方在哪里?静态标记


在这里插入图片描述

前言、Vue3的核心变化

  • Typescript,
  • Proxy响应式,
  • Composition解决代码反复横跳
  • 虚拟DOM

一、Vue3相比Vue2的优势

  • 1、速度更快 ------- 详细说明见第四大点,Vue3的虚拟DOM

    1、重写了虚拟Dom实现
    2、编译模板的优化
    3、更高效的组件初始化
    4、undate性能提高1.3~25、SSR速度提高了2~3
  • 2、体积减少
    通过webpack的tree-shaking功能,可以将无用模块“剪辑”,仅打包需要的,这样有两大好处:

    1、对开发人员,不必担忧项目整体体积过大
    
    2、对使用者,打包出来的包体积变小了
    
  • 3、更易维护

    1、compositon Api可与现有的Options API一起使用
    2、VUE3是基于typescript编写的,可以享受到自动的类型定义提示
    
  • 4、更接近原生
    可以自定义渲染 API
    在这里插入图片描述

  • 5、更易使用

二、Vue3.0变化的三大点

1、监测机制的改变:用Proxy替换Object.defineProperty

关于Proxy,一定程度上会带来的性能上的提升,因为传统的原型链拦截的方法,无法检测对象及数组的一些更新操作,但使用Proxy又带来了浏览器兼容问题。

Proxy 是什么
  • Proxy为 构造函数,用来生成 Proxy实例

    var proxy = new Proxy(target, handler)
    //target 表示所要拦截的目标对象(任何类型的对象,包括原生数组,函数)
    // handler通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为
    
  • 关于handler拦截属性,有如下13种

    • 1、get(对象属性的读取)、
    • 2、set(对象属性的设置)、
    • 3、apply(对函数的调用call、apply操作进行拦截)、
    • 4、has( 用于拦截hasProperty操作,返回一个布尔值)、
    • 5、deleteProperty (拦截delete操作,返回一个布尔值)
    • 6、defineProperty ( 拦截Object.defineProperty操作)
    • 7、getOwnPropertyDescriptor (用于拦截Object.getOwnPropertyDescriptor(),返回一个属性描述对象或者undefined)
    • 8、getPrototypeOf (用于拦截获取对象的原型)
    • 9、isExtensible (拦截Object.isExtensible()操作)
    • 10、ownKeys (用于拦截对象自身属性的读取操作,比如:Object.keys ()、Object.getOwnPropertySymbols ()、Object.getOwnPropertyNames ())
    • 11、preventExtensions (该方法拦截 Object.preventExtensions () ,该方法必须返回个布尔值)
    • 12、setPrototypeOf ( Object.setPrototypeOf 方法 )
    • 13、construct (拦截 new 操作符命令)
  • 若需要在Proxy内部调用对象的默认行为,建议使用Reflect,

    var person = {
          
          
     name: "张三"
    };
    
    var proxy = new Proxy(person, {
          
          
      get: function(target, propKey) {
          
          
        return Reflect.get(target,propKey)
      }
    });
    
    proxy.name // "张三"
    

proxy更多了解,请参考https://mp.weixin.qq.com/s/rIqznB3WXT6M4T0YQb6CQA

Proxy 区别于 Object.definedProperty
  • 是否可以监听属性的读写、删除、方法的调用
    Object.defineProperty 只能监听到属性的读写,而 Proxy 除读写外,还可以监听属性的删除,方法的调用等。

  • 是否可以监听数组、对象的变化
    Object.defineProperty 无法监测数组、对象的变化。而 Proxy 可以直接监视数组、对象的变化。

    Vue中是通过 对重写数组/对象的方法进行重写来实现监听数组/对象的变化的

  • 监听方式
    Proxy 是以非入侵的方式监管了对象的读写,而 defineProperty 需要按特定的方式定义对象的属性。

    let list = [1, 2, 3];
    let listproxy = new Proxy(list, {
        set(target, property, value) {
            target[property] = value;
            return true; // 标识设置成功
        }
    });
    
    list.push(4);
    
  • Proxy对象可以拦截什么?
    总共13个,见上方。

详细说明参考链接:https://blog.csdn.net/weixin_42724176/article/details/104811337

2、模板方面

模板方面没有大的变更,只改了作用域插槽,
2.x 的机制导致作用域插槽变了,父组件也会重新渲染
3.0 把作用域插槽改成了函数的方式,这样只会影响子组件的重新渲染,提升了渲染的性能。

3、对象式的组件声明方式

Vue2.x 中的组件是通过声明的方式传入一系列 option
Vue3.0 修改了组件的声明方式,改成了类式的写法,这样使得和 TypeScript 的结合变得很容易。

TypeScript遵循最新的 ES6、 ES5 规范,从语言层面上扩展了JavaScript的语法。 (比如来说,javascript为弱类型语言,而typescript则可以通过类型注释来提供编译时的静态类型检查,从而一定程度上防止报错)

typescript对比javascript,参考链接
https://www.jianshu.com/p/0dfbcd4a0757

4、其它方面的更改

1). 支持自定义渲染器,从而使得 weex 可以通过自定义渲染器的方式来扩展,而不是直接 fork 源码来改的方式。

2). 支持 Fragment(多个根节点) 和 Protal(在 dom 其他部分渲染组建内容)组件,针对一些特殊的场景做了处理。

3). 基于 treeshaking 优化,提供了更多的内置功能

参考链接:
https://www.jianshu.com/p/4db4b191de06

三、非兼容变更

1、模板指令

  • 组件上 v-model 用法已更改
  • <template v-for>和 非 v-for节点上key用法已更改
  • 在同一元素上使用的 v-if 和 v-for 优先级已更改
  • v-bind=“object” 现在排序敏感
  • v-for 中的 ref 不再注册 ref 数组

2、组件

  • 只能使用普通函数创建功能组件
  • 异步组件现在需要 defineAsyncComponent 方法来创建

四、Vue3的虚拟dom

Vue3性能的优化,具体表现为

  • upadte性能提升1.3~2倍,
  • ssr(服务器端渲染)提升2~3倍

Vue3编译速度上,性能优化的地方

  • 编译模版的静态标记
  • 内联事件缓存

1、编译模版的静态标记

我们来看一段很常见的代码

<div id="app">
    <h1>技术摸鱼</h1>
    <p>今天天气真不错</p>
    <div>{
    
    {
    
    name}}</div>
</div>

vue2中会解析

function render() {
    
    
  with(this) {
    
    
    return _c('div', {
    
    
      attrs: {
    
    
        "id": "app"
      }
    }, [_c('h1', [_v("技术摸鱼")]), _c('p', [_v("今天天气真不错")]), _c('div', [_v(
      _s(name))])])
  }
}

其中前面两个标签是完全静态的,后续的渲染中不会产生任何变化
Vue2中依然使用_c新建成vdom,在diff的时候需要对比,有一些额外的性能损耗

vue3中的解析结果

import {
    
     createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache) {
    
    
  return (_openBlock(), _createBlock("div", {
    
     id: "app" }, [
    _createVNode("h1", null, "技术摸鱼"),
    _createVNode("p", null, "今天天气真不错"),
    _createVNode("div", null, _toDisplayString(_ctx.name), 1 /* TEXT */)
  ]))
}
// Check the console for the AST

_createVNode新增第四个参数:

  • 如果是静态节点,则不添加第四个参数,则在对比时不遍历,
  • 如果非静态节点,则根据动态变化的地方,添加不同的标记,比如:text,props等动态变化,则添加不同的标记,这样再diff的时候,只需要对比text或者props,不用再做无谓的props遍历,这样update性能就会提高。
  • 如果一个节点是有多个动态变化的地方,比如说既有id的动态绑定,又有text的绑定,根据位运算符进行组合即可,比如:
<div id="app">
    <h1>技术摸鱼</h1>
    <p>今天天气真不错</p>
    <div :id="userid"">{
    
    {
    
    name}}</div>
</div>

编译后

import {
    
     createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache) {
    
    
  return (_openBlock(), _createBlock("div", {
    
     id: "app" }, [
    _createVNode("h1", null, "技术摸鱼"),
    _createVNode("p", null, "今天天气真不错"),
    _createVNode("div", {
    
    
      id: _ctx.userid,
      "\"": ""
    }, _toDisplayString(_ctx.name), 9 /* TEXT, PROPS */, ["id"])
  ]))
}

text是1,props是8,组合在一起就是9,我们可以简单的通过位运算来判定需要做text和props的判断, 按位与即可,只要不是0就是需要比较

在这里插入图片描述

Vue3静态标记不对比,提高更新渲染速度的示意图
在这里插入图片描述

2、事件缓存

绑定的@click会存在缓存里 链接

<div id="app">
  <button @click="handleClick">戳我</button>
</div>

编译后

export function render(_ctx, _cache) {
    
    
  return (_openBlock(), _createBlock("div", {
    
     id: "app" }, [
    _createVNode("button", {
    
    
      onClick: _cache[1] || (_cache[1] = $event => (_ctx.handleClick($event)))
    }, "戳我")
  ]))
}

五、vue3和react fiber的vdom

1、Vue2.x

引入vdom,控制了颗粒度,组件层面走watcher通知, 组件内部走vdom做diff,既不会有太多watcher,也不会让vdom的规模过大,这样就不会使diff超过16ms。
在这里插入图片描述

2、React 16 Fiber

React走了另外一条路,既然主要问题是diff导致卡顿,于是React走了类似requestIdleCallback的cpu调度的逻辑,**把vdom这棵树,变成了链表**,利用浏览器的空闲时间来做diff,如果超过了16ms,有动画或者用户交互的任务,就把主进程控制权还给浏览器,等空闲了继续
在这里插入图片描述

Vue3通过Proxy响应式+组件内部vdom+静态标记,把任务颗粒度控制的足够细致,所以也不太需要React的Fiber了

参考链接:https://mp.weixin.qq.com/s/dgC6zOkpo1ghyUYS680oWw

参考链接:https://juejin.cn/post/6844904134647234568

猜你喜欢

转载自blog.csdn.net/yiyueqinghui/article/details/113617669