Vue3.0学习 - 第一节,diff算法、静态标记

第一节:

# Diff 

静态标记

Vue3 中仅对静态标记标记对象进行比较

动态绑定

<div>
  <p>Xmo</p>
  <p>{{kkl}}</p>
  <p>Xmo</p>
  <p>1234</p>
  <img :src="img">
</div>
import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", null, [
    _createVNode("p", null, "Xmo"),
    _createVNode("p", null, _toDisplayString(_ctx.kkl), 1 /* TEXT */),
    _createVNode("p", null, "Xmo"),
    _createVNode("p", null, "1234"),
    _createVNode("img", { src: _ctx.img }, null, 8 /* PROPS */, ["src"])
  ]))
}

// Check the console for the AST

可以看到,源码中,对 msg 设计了静态标记,这里是1,后面跟注释 TEXT ,代表这个标签的 TEXT 数据是会动态变化的。(动态变化的东西反而叫静态标记,可还行)

_createVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)
  • Vue2 中的虚拟dom是进行全量的杜比
  • Vue3 新增了静态标记(PatchFlag)
    • 只比对带有 PF 的节点
    • 并且通过 Flag 的信息得知当前节点要比对的具体内容

静态提升

  • vue2中无论元素是否参与更新,每次都会重新创建,然后在渲染
  • vue3中对于不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用即可

对上面的代码开启静态提升(hoistStatic)

开启位置

开启后的效果

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

const _hoisted_1 = /*#__PURE__*/_createVNode("p", null, "Xmo", -1 /* HOISTED */)
const _hoisted_2 = /*#__PURE__*/_createVNode("p", null, "Xmo", -1 /* HOISTED */)
const _hoisted_3 = /*#__PURE__*/_createVNode("p", null, "Xmo", -1 /* HOISTED */)

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", null, [
    _hoisted_1,
    _hoisted_2,
    _hoisted_3,
    _createVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */),
    _createVNode("img", { src: _ctx.srci }, null, 8 /* PROPS */, ["src"])
  ]))
}

// Check the console for the AST

将静态内容提取出来,变成常量再进行赋值,只需创建一次,后面直接复用,

非静态提升:每次创建都要重新创建

静态提升:静态内容只需创建一次,后面直接复用

  • 以后每次进行render的时候,就不会重复创建这些静态的内容,而是直接从一开始就创建好的常量中取就行了。

#事件侦听器缓存

写一段带事件的代码

<div>
  <button @click="onClick">btn</button>
</div>
import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", null, [
    _createVNode("button", { onClick: _ctx.onClick }, "btn", 8 /* PROPS */, ["onClick"])
  ]))
}

// Check the console for the AST

这里我们还没有开启事件监听缓存,熟悉的静态标记    8 /* PROPS */     出现了,它将标签的 Props (属性) 标记动态属性。

如果我们存在属性不会改变,不希望这个属性被标记为动态,那么就需要 cacheHandler 的出场了。

开启后

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

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", null, [
    _createVNode("button", {
      onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.onClick && _ctx.onClick(...args)))
    }, "btn")
  ]))
}

// Check the console for the AST

_createVnode 的第二个属性,从

{ onClick: _ctx.onClick }

变为了

{ onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.onClick(...args))) }

它的意思很明显,onClick 方法被存入 cache。在使用的时候,如果能在缓存中找到这个方法,那么它将直接被使用。如果找不到,那么将这个方法注入缓存。总之,就是把方法给缓存了。

如果有多个标签、方法,效果

<div>
  <button @click="onClick" @mouseover="onMouseover">btn</button>
  <button @click="onClick1">btn</button>
</div>
import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", null, [
    _createVNode("button", {
      onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.onClick && _ctx.onClick(...args))),
      onMouseover: _cache[2] || (_cache[2] = (...args) => (_ctx.onMouseover && _ctx.onMouseover(...args)))
    }, "btn", 32 /* HYDRATE_EVENTS */),
    _createVNode("button", {
      onClick: _cache[3] || (_cache[3] = (...args) => (_ctx.onClick1 && _ctx.onClick1(...args)))
    }, "btn")
  ]))
}

// Check the console for the AST

值得注意的是,在测试过程中,只要监听了除了 click 以外的方法,都会添加 32 /* HYDRATE_EVENTS */ 事件监听静态标记(事件的方法静态的,但监听的事件则是动态的【onMouseover是缓存的,而mouseover事件则不是】)。

总之,静态提升之后,事件就不会在 diff 算法中进行比较了。

 

 

 

patchFlags 是什么

export const enum PatchFlags {
  // 动态文字内容
  TEXT = 1,

  // 动态 class
  CLASS = 1 << 1,

  // 动态样式
  STYLE = 1 << 2,

  // 动态 props
  PROPS = 1 << 3,

  // 有动态的key,也就是说props对象的key不是确定的
  FULL_PROPS = 1 << 4,

  // 合并事件
  HYDRATE_EVENTS = 1 << 5,

  // children 顺序确定的 fragment
  STABLE_FRAGMENT = 1 << 6,

  // children中有带有key的节点的fragment
  KEYED_FRAGMENT = 1 << 7,

  // 没有key的children的fragment
  UNKEYED_FRAGMENT = 1 << 8,

  // 只有非props需要patch的,比如`ref`
  NEED_PATCH = 1 << 9,

  // 动态的插槽
  DYNAMIC_SLOTS = 1 << 10,

  // SPECIAL FLAGS -------------------------------------------------------------

  // 以下是特殊的flag,不会在优化中被用到,是内置的特殊flag

  // 表示他是静态节点,他的内容永远不会改变,对于hydrate的过程中,不会需要再对其子节点进行diff
  HOISTED = -1,

  // 用来表示一个节点的diff应该结束
  BAIL = -2,
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随便起的名字也被占用

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值