🏰

vue3事件缓存(cacheHandlers)

<div @click="clickEvent">Hello World!</div>
vue2编译成render函数
(_ctx, _cache) => { return (_openBlock(), _createElementBlock("div", { onClick: _ctx.clickEvent }, "Hello World!", 8 /* PROPS */, ["onClick"])) } // Check the console for the AST
 
vue3经过编程render函数
import { openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue" export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createElementBlock("div", { onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.clickEvent && _ctx.clickEvent(...args))) }, "Hello World!")) } // Check the console for the AST

为什么要单独加缓存?

更新事件的似乎,如果需要卸载事件,太消耗性能,如果我们可以直接更改老的事件的内存地址,何乐而不为
export function patchEvent( el: Element & { _vei?: Record<string, Invoker | undefined> }, rawName: string, prevValue: EventValue | null, nextValue: EventValue | null, instance: ComponentInternalInstance | null = null ) { // vei = vue event invokers const invokers = el._vei || (el._vei = {}) const existingInvoker = invokers[rawName] if (nextValue && existingInvoker) { // patch existingInvoker.value = nextValue } else { const [name, options] = parseName(rawName) if (nextValue) { // add const invoker = (invokers[rawName] = createInvoker(nextValue, instance)) addEventListener(el, name, invoker, options) } else if (existingInvoker) { // remove removeEventListener(el, name, existingInvoker, options) invokers[rawName] = undefined } } }
上面代码做的事情
  1. 给当前的el上挂载一个_vei属性(vue event invokers)去缓存当前这条元素身上的事件
  1. 进行diff比对的时候,如果有老的同名的事件就直接替换老的事件的内存地址(这样就少了一次移除事件+新增事件的性能消耗)
  1. 如果没有就算是新增的事件,并且如果新增的事件不存在,才真正去移除老的事件,如果新增的事件在,并且没有老的事件绑定,则重新创建缓存并且绑定到el上
invoker里面的结构类似
{ click:[event....] change:[event...] }