vue3.0性能优化点之静态标记(PatchFlag)
vue3.0性能优化点之静态标记(PatchFlag)
关注Vue3源码库的童鞋应该有注意到,2021.11月2号Vue更新到了3.2.21版本,自Vue3发布以来,一直在不断的迭代完善着,Vue3的GitHub仓库已有25.7k Star, 主流UI框架如:Ant Design of Vue、element plus、Vant 等已实现了对Vue3的支持
关注颇高的Vue3都有哪些亮点呢?
性能上快了 1.3 ~ 2倍是Vue3的一大亮点,而本文就主要记录下 提升性能的一个措施:静态标记
在Vue2中,每次更新diff,都是全量对比,Vue3则只对比带有标记的,这样大大减少了非动态内容的对比消耗
在Vue3中有哪些静态标记?
在packages/shared/src/patchFlags.ts文件里,静态标记枚举了十几个类型,如下:
/**
* Patch flags are optimization hints generated by the compiler.
* when a block with dynamicChildren is encountered during diff, the algorithm
* enters "optimized mode". In this mode, we know that the vdom is produced by
* a render function generated by the compiler, so the algorithm only needs to
* handle updates explicitly marked by these patch flags.
*
* Patch flags can be combined using the | bitwise operator and can be checked
* using the & operator, e.g.
*
* ```js
* const flag = TEXT | CLASS
* if (flag & TEXT) { ... }
* ```
*
* Check the `patchElement` function in '../../runtime-core/src/renderer.ts' to see how the
* flags are handled during diff.
*/
export const enum PatchFlags {
/**
* Indicates an element with dynamic textContent (children fast path)
*/
TEXT = 1,
/**
* Indicates an element with dynamic class binding.
*/
CLASS = 1 << 1,
/**
* Indicates an element with dynamic style
* The compiler pre-compiles static string styles into static objects
* + detects and hoists inline static objects
* e.g. style="color: red" and :style="{ color: 'red' }" both get hoisted as
* const style = { color: 'red' }
* render() { return e('div', { style }) }
*/
STYLE = 1 << 2,
/**
* Indicates an element that has non-class/style dynamic props.
* Can also be on a component that has any dynamic props (includes
* class/style). when this flag is present, the vnode also has a dynamicProps
* array that contains the keys of the props that may change so the runtime
* can diff them faster (without having to worry about removed props)
*/
PROPS = 1 << 3,
/**
* Indicates an element with props with dynamic keys. When keys change, a full
* diff is always needed to remove the old key. This flag is mutually
* exclusive with CLASS, STYLE and PROPS.
*/
FULL_PROPS = 1 << 4,
/**
* Indicates an element with event listeners (which need to be attached
* during hydration)
*/
HYDRATE_EVENTS = 1 << 5,
/**
* Indicates a fragment whose children order doesn't change.
*/
STABLE_FRAGMENT = 1 << 6,
/**
* Indicates a fragment with keyed or partially keyed children
*/
KEYED_FRAGMENT = 1 << 7,
/**
* Indicates a fragment with unkeyed children.
*/
UNKEYED_FRAGMENT = 1 << 8,
/**
* Indicates an element that only needs non-props patching, e.g. ref or
* directives (onVnodeXXX hooks). since every patched vnode checks for refs
* and onVnodeXXX hooks, it simply marks the vnode so that a parent block
* will track it.
*/
NEED_PATCH = 1 << 9,
/**
* Indicates a component with dynamic slots (e.g. slot that references a v-for
* iterated value, or dynamic slot names).
* Components with this flag are always force updated.
*/
DYNAMIC_SLOTS = 1 << 10,
/**
* Indicates a fragment that was created only because the user has placed
* comments at the root level of a template. This is a dev-only flag since
* comments are stripped in production.
*/
DEV_ROOT_FRAGMENT = 1 << 11,
/**
* SPECIAL FLAGS -------------------------------------------------------------
* Special flags are negative integers. They are never matched against using
* bitwise operators (bitwise matching should only happen in branches where
* patchFlag > 0), and are mutually exclusive. When checking for a special
* flag, simply check patchFlag === FLAG.
*/
/**
* Indicates a hoisted static vnode. This is a hint for hydration to skip
* the entire sub tree since static content never needs to be updated.
*/
HOISTED = -1,
/**
* A special flag that indicates that the diffing algorithm should bail out
* of optimized mode. For example, on block fragments created by renderSlot()
* when encountering non-compiler generated slots (i.e. manually written
* render functions, which should always be fully diffed)
* OR manually cloneVNodes
*/
BAIL = -2
}
/**
* dev only flag -> name mapping
*/
export const PatchFlagNames = {
[PatchFlags.TEXT]: `TEXT`,
[PatchFlags.CLASS]: `CLASS`,
[PatchFlags.STYLE]: `STYLE`,
[PatchFlags.PROPS]: `PROPS`,
[PatchFlags.FULL_PROPS]: `FULL_PROPS`,
[PatchFlags.HYDRATE_EVENTS]: `HYDRATE_EVENTS`,
[PatchFlags.STABLE_FRAGMENT]: `STABLE_FRAGMENT`,
[PatchFlags.KEYED_FRAGMENT]: `KEYED_FRAGMENT`,
[PatchFlags.UNKEYED_FRAGMENT]: `UNKEYED_FRAGMENT`,
[PatchFlags.NEED_PATCH]: `NEED_PATCH`,
[PatchFlags.DYNAMIC_SLOTS]: `DYNAMIC_SLOTS`,
[PatchFlags.DEV_ROOT_FRAGMENT]: `DEV_ROOT_FRAGMENT`,
[PatchFlags.HOISTED]: `HOISTED`,
[PatchFlags.BAIL]: `BAIL`
}
简单总结翻译一下:
export const enum PatchFlags {
TEXT = 1,// 1 动态的文本节点
CLASS = 1 << 1, // 2 动态的 class
STYLE = 1 << 2, // 4 动态的 style
PROPS = 1 << 3, // 8 动态属性,不包括类名和样式
FULL_PROPS = 1 << 4, // 16 动态 key,当 key 变化时需要完整的 diff 算法做比较
HYDRATE_EVENTS = 1 << 5, // 32 表示带有事件监听器的节点
STABLE_FRAGMENT = 1 << 6, // 64 一个不会改变子节点顺序的 Fragment
KEYED_FRAGMENT = 1 << 7, // 128 带有 key 属性的 Fragment
UNKEYED_FRAGMENT = 1 << 8, // 256 子节点没有 key 的 Fragment
NEED_PATCH = 1 << 9, // 512 表示只需要non-props修补的元素 (non-props不知道怎么翻才恰当~)
DYNAMIC_SLOTS = 1 << 10, // 1024 动态的solt
DEV_ROOT_FRAGMENT = 1 << 11, //2048 表示仅因为用户在模板的根级别放置注释而创建的片段。 这是一个仅用于开发的标志,因为注释在生产中被剥离。
//以下两个是特殊标记
HOISTED = -1, // 表示已提升的静态vnode,更新时调过整个子树
BAIL = -2 // 指示差异算法应该退出优化模式
}
备注: 1<<n 表示十六进制中 1向左移n位, 如: 1<<3 ,则表示 0001 变成 0100 即:8
我们在Vue Template Explorer 上做测试,我们可以直观的看到对应的静态标记
以上是vue3 静态标记的内容
vue3是一个大版本的改动,在性能优化肯定不止这一项,比如还有:静态提升(hoistStatic)、事件监听缓存(cacheHandler)、SSR服务端渲染速度提升2~3倍、静态节点(staticNode)等等,可以在 Vue Template Explorer 的右上角的Options查看这些优化的差别
静态标记的内容到此结束啦
注意: 记录一个很多人的误解,觉得Vue3的setup 方法的出现, vue2的beforeCreate 和 created生命周期就去掉了没有了,根据vue团队在Vue Mastery上的讲解, 实际上setup函数是在生命周期之前执行的,但确实beforeCreate和created中的代码基本都可以直接写在setup中,只能说setup基本能做那两个生命周期的事情,但这两个生命周期在vue3也是可以继续用的.
ps:成长路上的简单记录,如有不恰当之处,欢迎交流!
更多推荐
所有评论(0)