vue3优化点

133 阅读2分钟

模板编译之静态提升

在vue生命周期钩子beforeCreate之前,会先依次做如下判断,确定组件的render函数:

  • 先执行setup如果返回值setupResult是function,取setupResult为render函数:instance.render = setupResult
  • 检查组件是否提供render选项,如果提供这个选项就是render函数
  • 上面都执行完了还没有render函数,则使用compile 编译template模板,生成render函数

模板编译步骤

  • vue实例化时,会先调用registerRuntimeCompiler注册模板编译函数compileToFunction
  • template模板字符串为key去缓存中查找是否存在已经编译好的render函数
  // 以template模板字符串作为key,缓存编译结果
  ...
  const key = template
  const cached = compileCache[key]
  if (cached) {
    return cached
  }
  ...
  • 缓存不存在,调用compile编译模板,分三步
    1. parsetemplate模板生成ast语法树

      image.png

    2. 翻译指令、过滤器

    3. 优化ast树,标记静态节点,并将静态节点提升至root

      image.png

    • 利用ast生成渲染函数体字符串code

        generate(
         ast,
         extend({}, options, {
           prefixIdentifiers
         })
       )
      
       // 利用ast生成的渲染函数体字符串,注意这里编译出来的是个函数体字符串
       const _Vue = Vue
        const { createElementVNode: _createElementVNode, createTextVNode: _createTextVNode } = _Vue
        // 提升到render外部的静态节点
        const _hoisted_1 = /*#__PURE__*/_createTextVNode(" 测试子组件之间的 ")
        const _hoisted_2 = /*#__PURE__*/_createElementVNode("p", null, "测试静态节点", -1 /* HOISTED */)
      
        return function render(_ctx, _cache) {
          with (_ctx) {
            const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, createTextVNode: _createTextVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
      
            return (_openBlock(), _createElementBlock("div", null, [
              _createElementVNode("button", null, [
                _hoisted_1,
                _createElementVNode("span", null, _toDisplayString(ag), 1 /* TEXT */)
              ]),
              _hoisted_2
            ]))
          }
        }
      
    1. 调用Function构造函数,传入上面生成的渲染函数体字符串,生成一个函数并调用生成render函数,利用闭包使静态节点只创建一次

       ...
       const render = (
         __GLOBAL__ ? new Function(code)() : new Function('Vue', code)(runtimeDom)
       ) as RenderFunction
      
       // mark the function as runtime compiled
       ;(render as InternalRenderFunction)._rc = true
      
       return (compileCache[key] = render)
       
      
         // 最终生成的render函数
         function render(_ctx, _cache) {
           with (_ctx) {
             const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, createTextVNode: _createTextVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
      
             return (_openBlock(), _createElementBlock("div", null, [
               _createElementVNode("button", null, [
                 _hoisted_1,
                 _createElementVNode("span", null, _toDisplayString(ag), 1 /* TEXT */)
               ]),
               _hoisted_2
             ]))
           }
         }
      
  1. 利用静态提升,将静态节点提升到创建render函数之前执行,render函数中只保留静态节点的引用,避免了后续触发组件更新时重复生成静态节点。
  2. 同时会缓存编译后的render函数,相同的模板只会编译一次

按需添加响应式

(待续)