import { createVNode as _createVNode, toDisplaySt._diff静态标记">
当前位置:   article > 正文

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

diff静态标记

第一节:

# Diff 

静态标记

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

动态绑定

  1. <div>
  2. <p>Xmo</p>
  3. <p>{{kkl}}</p>
  4. <p>Xmo</p>
  5. <p>1234</p>
  6. <img :src="img">
  7. </div>
  1. import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"
  2. export function render(_ctx, _cache, $props, $setup, $data, $options) {
  3. return (_openBlock(), _createBlock("div", null, [
  4. _createVNode("p", null, "Xmo"),
  5. _createVNode("p", null, _toDisplayString(_ctx.kkl), 1 /* TEXT */),
  6. _createVNode("p", null, "Xmo"),
  7. _createVNode("p", null, "1234"),
  8. _createVNode("img", { src: _ctx.img }, null, 8 /* PROPS */, ["src"])
  9. ]))
  10. }
  11. // 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)

开启位置

开启后的效果

  1. import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"
  2. const _hoisted_1 = /*#__PURE__*/_createVNode("p", null, "Xmo", -1 /* HOISTED */)
  3. const _hoisted_2 = /*#__PURE__*/_createVNode("p", null, "Xmo", -1 /* HOISTED */)
  4. const _hoisted_3 = /*#__PURE__*/_createVNode("p", null, "Xmo", -1 /* HOISTED */)
  5. export function render(_ctx, _cache, $props, $setup, $data, $options) {
  6. return (_openBlock(), _createBlock("div", null, [
  7. _hoisted_1,
  8. _hoisted_2,
  9. _hoisted_3,
  10. _createVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */),
  11. _createVNode("img", { src: _ctx.srci }, null, 8 /* PROPS */, ["src"])
  12. ]))
  13. }
  14. // Check the console for the AST

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

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

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

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

#事件侦听器缓存

写一段带事件的代码

  1. <div>
  2. <button @click="onClick">btn</button>
  3. </div>
  1. import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"
  2. export function render(_ctx, _cache, $props, $setup, $data, $options) {
  3. return (_openBlock(), _createBlock("div", null, [
  4. _createVNode("button", { onClick: _ctx.onClick }, "btn", 8 /* PROPS */, ["onClick"])
  5. ]))
  6. }
  7. // Check the console for the AST

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

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

开启后

  1. import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"
  2. export function render(_ctx, _cache, $props, $setup, $data, $options) {
  3. return (_openBlock(), _createBlock("div", null, [
  4. _createVNode("button", {
  5. onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.onClick && _ctx.onClick(...args)))
  6. }, "btn")
  7. ]))
  8. }
  9. // Check the console for the AST

_createVnode 的第二个属性,从

{ onClick: _ctx.onClick }

变为了

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

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

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

  1. <div>
  2. <button @click="onClick" @mouseover="onMouseover">btn</button>
  3. <button @click="onClick1">btn</button>
  4. </div>
  1. import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"
  2. export function render(_ctx, _cache, $props, $setup, $data, $options) {
  3. return (_openBlock(), _createBlock("div", null, [
  4. _createVNode("button", {
  5. onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.onClick && _ctx.onClick(...args))),
  6. onMouseover: _cache[2] || (_cache[2] = (...args) => (_ctx.onMouseover && _ctx.onMouseover(...args)))
  7. }, "btn", 32 /* HYDRATE_EVENTS */),
  8. _createVNode("button", {
  9. onClick: _cache[3] || (_cache[3] = (...args) => (_ctx.onClick1 && _ctx.onClick1(...args)))
  10. }, "btn")
  11. ]))
  12. }
  13. // Check the console for the AST

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

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

 

 

 

patchFlags 是什么

  1. export const enum PatchFlags {
  2. // 动态文字内容
  3. TEXT = 1,
  4. // 动态 class
  5. CLASS = 1 << 1,
  6. // 动态样式
  7. STYLE = 1 << 2,
  8. // 动态 props
  9. PROPS = 1 << 3,
  10. // 有动态的key,也就是说props对象的key不是确定的
  11. FULL_PROPS = 1 << 4,
  12. // 合并事件
  13. HYDRATE_EVENTS = 1 << 5,
  14. // children 顺序确定的 fragment
  15. STABLE_FRAGMENT = 1 << 6,
  16. // children中有带有key的节点的fragment
  17. KEYED_FRAGMENT = 1 << 7,
  18. // 没有key的children的fragment
  19. UNKEYED_FRAGMENT = 1 << 8,
  20. // 只有非props需要patch的,比如`ref`
  21. NEED_PATCH = 1 << 9,
  22. // 动态的插槽
  23. DYNAMIC_SLOTS = 1 << 10,
  24. // SPECIAL FLAGS -------------------------------------------------------------
  25. // 以下是特殊的flag,不会在优化中被用到,是内置的特殊flag
  26. // 表示他是静态节点,他的内容永远不会改变,对于hydrate的过程中,不会需要再对其子节点进行diff
  27. HOISTED = -1,
  28. // 用来表示一个节点的diff应该结束
  29. BAIL = -2,
  30. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/133833?site
推荐阅读
相关标签
  

闽ICP备14008679号