vue3的runtime-core-ShapeFlags

240 阅读2分钟

ShapeFlags呢主要是用来做type类型的,主要做的是性能优化,用映射的方式可读性会比较高,这里ShapeFlags使用的是位运算,位运算在其他地方使用起来也是很方便的,最典型的例子就是权限校验,使用位运算会简化很多,性能也要比映射高出不少,但可读性不高,但总得迈出这一步,学习一下位运算

ShapeFlags

ShapeFlags是用来做type类型的,判断场景会比较多,赋值也会很方便

位运算也不难,| 和 & 这两个符号做处理

结合ShapeFlags.ts来看更清晰易解

| 用来赋值

两者为0才为0

0001 | 0010
  
// 0001
// 0010
// 0000

& 用来判断

两者为1才为1

0001 & 0011
  
// 0001
// 0011
// 0001

ShapeFlags

export const enum ShapeFlags {

    ELEMENT = 1,                    // -> 0001

    STATEFUL_COMPONENT = 1 << 1,    // -> 0010

    TEXT_CHILDREN = 1 << 2,         // -> 0100

    ARRAY_CHILDREN = 1 << 3,        // -> 1000

}

这里的 << 是移位,1向左移几位,>> 同理

vnode.ts

export function createVNode(type, props?, children?) {
    const vnode = {
        type,
        props,
        children,
        shapeFlag: getShapeFlag(type), // 创建类型标识
        el: null
    }
    // children
    if (typeof children === 'string') {
        // 等同于 vnode.shapeFlag = vnode.shapeFlag | ShapeFlags.TEXT_CHILDREN
        vnode.shapeFlag |= ShapeFlags.TEXT_CHILDREN // 判断后进行赋值
    }
    else if (Array.isArray(children)) {
        vnode.shapeFlag |= ShapeFlags.ARRAY_CHILDREN
    }

    return vnode
}

export function getShapeFlag(type) {
    return typeof type === 'string'
        ? ShapeFlags.ELEMENT
        : ShapeFlags.STATEFUL_COMPONENT
}

使用的话就特别简单了,把判断、赋值的地方改动一下,运用位运算的方式进行赋值、判断操作

renderer.ts


function patch(vnode: any, container: any) {
    const { type, props, children, shapeFlag } = vnode
    // 判断vnode是不是一个element
    if (shapeFlag & ShapeFlags.ELEMENT) { //使用 & 进行判断结合上文代入
        // 处理element
        processElement(vnode, container)
    } else if (shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
        // 处理组件
        processComponent(vnode, container)
    }
}

function mountElement(vnode: any, container: any) {
    const { type, props, children, shapeFlag } = vnode
    const el = (vnode.el = document.createElement(type))

    // string array<TODO>
    if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
        el.textContent = children
    }
    else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
        mountChildren(vnode, el)
    }


    for (const key in props) {
        const value = props[key]
        el.setAttribute(key, value)
    }

    container.append(el)
}

上文就把之前写的两个判断改为位运算方式进行判断、赋值

结语

位运算在性能方面其实是天花板了,但是因为可读性原因,所以很多人不愿意去使用,对概念不清楚的情况下很容易写出错漏百出的代码,转而使用映射来实现需求,所以如果对性能方面有需求,使用位运算其实是很不错的选择,没有之一。要学习更细节的位运算,还是需要自己去查资料,敲一敲才能够掌握位运算,熟练使用位运算。最后感谢,动动小手🙂