]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat: skip constant trees and memoize fn
authorEvan You <yyx990803@gmail.com>
Sun, 28 Oct 2018 20:41:29 +0000 (16:41 -0400)
committerEvan You <yyx990803@gmail.com>
Sun, 28 Oct 2018 20:41:29 +0000 (16:41 -0400)
packages/runtime-core/src/createRenderer.ts
packages/runtime-core/src/optional/memoize.ts [new file with mode: 0644]

index e16424f656040c5be209e44785b5c5c509688708..d749f497a9694050f66b0ad9f139288fbac0ea74 100644 (file)
@@ -7,7 +7,6 @@ import {
   MountedVNode,
   RenderNode,
   createTextVNode,
-  cloneVNode,
   Ref,
   VNodeChildren
 } from './vdom'
@@ -135,10 +134,6 @@ export function createRenderer(options: RendererOptions) {
     endNode: RenderNode | null
   ) {
     for (let i = 0; i < children.length; i++) {
-      let child = children[i]
-      if (child.el) {
-        children[i] = child = cloneVNode(child)
-      }
       mount(children[i], container, contextVNode, isSVG, endNode)
     }
   }
@@ -346,6 +341,11 @@ export function createRenderer(options: RendererOptions) {
     contextVNode: MountedVNode | null,
     isSVG: boolean
   ) {
+    if (prevVNode === nextVNode) {
+      nextVNode.el = prevVNode.el
+      return
+    }
+
     const nextFlags = nextVNode.flags
     const prevFlags = prevVNode.flags
 
@@ -768,19 +768,12 @@ export function createRenderer(options: RendererOptions) {
     for (i; i < commonLength; i++) {
       nextChild = nextChildren[i]
       prevChild = prevChildren[i]
-      if (nextChild.el) {
-        nextChildren[i] = nextChild = cloneVNode(nextChild)
-      }
       patch(prevChild, nextChild, container, contextVNode, isSVG)
       prevChildren[i] = nextChild as MountedVNode
     }
     if (prevLength < nextLength) {
       for (i = commonLength; i < nextLength; i++) {
-        nextChild = nextChildren[i]
-        if (nextChild.el) {
-          nextChildren[i] = nextChild = cloneVNode(nextChild)
-        }
-        mount(nextChild, container, contextVNode, isSVG, endNode)
+        mount(nextChildren[i], container, contextVNode, isSVG, endNode)
       }
     } else if (prevLength > nextLength) {
       for (i = commonLength; i < prevLength; i++) {
@@ -810,9 +803,6 @@ export function createRenderer(options: RendererOptions) {
     outer: {
       // Sync nodes with the same key at the beginning.
       while (prevVNode.key === nextVNode.key) {
-        if (nextVNode.el) {
-          nextChildren[j] = nextVNode = cloneVNode(nextVNode)
-        }
         patch(prevVNode, nextVNode, container, contextVNode, isSVG)
         prevChildren[j] = nextVNode as MountedVNode
         j++
@@ -828,9 +818,6 @@ export function createRenderer(options: RendererOptions) {
 
       // Sync nodes with the same key at the end.
       while (prevVNode.key === nextVNode.key) {
-        if (nextVNode.el) {
-          nextChildren[nextEnd] = nextVNode = cloneVNode(nextVNode)
-        }
         patch(prevVNode, nextVNode, container, contextVNode, isSVG)
         prevChildren[prevEnd] = nextVNode as MountedVNode
         prevEnd--
@@ -849,11 +836,7 @@ export function createRenderer(options: RendererOptions) {
         const nextNode =
           nextPos < nextLength ? nextChildren[nextPos].el : endNode
         while (j <= nextEnd) {
-          nextVNode = nextChildren[j]
-          if (nextVNode.el) {
-            nextChildren[j] = nextVNode = cloneVNode(nextVNode)
-          }
-          j++
+          nextVNode = nextChildren[j++]
           mount(nextVNode, container, contextVNode, isSVG, nextNode)
         }
       }
@@ -896,9 +879,6 @@ export function createRenderer(options: RendererOptions) {
                 } else {
                   pos = j
                 }
-                if (nextVNode.el) {
-                  nextChildren[j] = nextVNode = cloneVNode(nextVNode)
-                }
                 patch(prevVNode, nextVNode, container, contextVNode, isSVG)
                 patched++
                 break
@@ -940,9 +920,6 @@ export function createRenderer(options: RendererOptions) {
               } else {
                 pos = j
               }
-              if (nextVNode.el) {
-                nextChildren[j] = nextVNode = cloneVNode(nextVNode)
-              }
               patch(prevVNode, nextVNode, container, contextVNode, isSVG)
               patched++
             } else if (!canRemoveWholeContent) {
@@ -971,9 +948,6 @@ export function createRenderer(options: RendererOptions) {
             if (sources[i] === 0) {
               pos = i + nextStart
               nextVNode = nextChildren[pos]
-              if (nextVNode.el) {
-                nextChildren[pos] = nextVNode = cloneVNode(nextVNode)
-              }
               nextPos = pos + 1
               mount(
                 nextVNode,
@@ -1002,9 +976,6 @@ export function createRenderer(options: RendererOptions) {
             if (sources[i] === 0) {
               pos = i + nextStart
               nextVNode = nextChildren[pos]
-              if (nextVNode.el) {
-                nextChildren[pos] = nextVNode = cloneVNode(nextVNode)
-              }
               nextPos = pos + 1
               mount(
                 nextVNode,
@@ -1119,8 +1090,8 @@ export function createRenderer(options: RendererOptions) {
       } else {
         platformRemoveChild(container, el)
       }
-      ;(vnode as any).el = null
     }
+    ;(vnode as any).el = null
   }
 
   function removeChildren(
@@ -1394,9 +1365,6 @@ export function createRenderer(options: RendererOptions) {
     container: any
   ): ComponentInstance | null {
     const prevVNode = container.vnode
-    if (vnode && vnode.el) {
-      vnode = cloneVNode(vnode)
-    }
     if (prevVNode == null) {
       if (vnode) {
         mount(vnode, container, null, false, null)
diff --git a/packages/runtime-core/src/optional/memoize.ts b/packages/runtime-core/src/optional/memoize.ts
new file mode 100644 (file)
index 0000000..0bfca68
--- /dev/null
@@ -0,0 +1,53 @@
+// Used for memoizing trees inside render functions.
+//
+// Example (equivalent of v-once):
+//
+//   render() {
+//     return memoize(h('div', this.msg), this, 0)
+//   }
+//
+// Memoize baesd on keys:
+//
+//   render() {
+//     return memoize(h('div', this.msg + this.count), this, 0, [this.msg])
+//   }
+
+import { Component } from '../component'
+import { warn } from '../warning'
+
+const memoizeMap = new WeakMap()
+
+export function memoize(
+  getter: () => any,
+  instance: Component,
+  id: number,
+  keys?: any[]
+): any {
+  if (__DEV__ && !Array.isArray(keys)) {
+    warn(
+      `keys passed to v-memo or memoize must be an array. Got ${String(keys)}`
+    )
+  }
+  let storage = memoizeMap.get(instance)
+  if (!storage) {
+    storage = []
+    memoizeMap.set(instance, storage)
+  }
+  const record = storage[id]
+  if (!record) {
+    const value = getter()
+    storage[id] = [value, keys]
+    return value
+  } else {
+    const [prevValue, prevKeys] = record
+    record[1] = keys
+    if (keys) {
+      for (let i = 0; i < keys.length; i++) {
+        if (keys[i] !== prevKeys[i]) {
+          return (record[0] = getter())
+        }
+      }
+    }
+    return prevValue
+  }
+}