]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: reduce bundle size
authorEvan You <yyx990803@gmail.com>
Wed, 7 Jul 2021 16:33:37 +0000 (12:33 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 16 Jul 2021 18:30:49 +0000 (14:30 -0400)
packages/reactivity/src/Dep.ts
packages/reactivity/src/effect.ts
packages/runtime-core/src/renderer.ts

index 1d735466fc4376dc469533c86ad76aa646081b8f..546f99e0f4e5a3374b8ca0447845250e56a4cf09 100644 (file)
@@ -1,4 +1,4 @@
-import { ReactiveEffect, getTrackOpBit } from './effect'
+import { ReactiveEffect, trackOpBit } from './effect'
 
 export type Dep = Set<ReactiveEffect> & TrackedMarkers
 
@@ -7,45 +7,51 @@ export type Dep = Set<ReactiveEffect> & TrackedMarkers
  * tracking recursion. One bit per level is used to define wheter the dependency
  * was/is tracked.
  */
-type TrackedMarkers = { wasTracked: number; newTracked: number }
-
-export function createDep(effects?: ReactiveEffect[]): Dep {
+type TrackedMarkers = {
+  /**
+   * wasTracked
+   */
+  w: number
+  /**
+   * newTracked
+   */
+  n: number
+}
+
+export const createDep = (effects?: ReactiveEffect[]): Dep => {
   const dep = new Set<ReactiveEffect>(effects) as Dep
-  dep.wasTracked = 0
-  dep.newTracked = 0
+  dep.w = 0
+  dep.n = 0
   return dep
 }
 
-export function wasTracked(dep: Dep): boolean {
-  return hasBit(dep.wasTracked, getTrackOpBit())
-}
-
-export function newTracked(dep: Dep): boolean {
-  return hasBit(dep.newTracked, getTrackOpBit())
-}
-
-export function setWasTracked(dep: Dep) {
-  dep.wasTracked = setBit(dep.wasTracked, getTrackOpBit())
-}
-
-export function setNewTracked(dep: Dep) {
-  dep.newTracked = setBit(dep.newTracked, getTrackOpBit())
-}
-
-export function resetTracked(dep: Dep) {
-  const trackOpBit = getTrackOpBit()
-  dep.wasTracked = clearBit(dep.wasTracked, trackOpBit)
-  dep.newTracked = clearBit(dep.newTracked, trackOpBit)
-}
-
-function hasBit(value: number, bit: number): boolean {
-  return (value & bit) > 0
-}
-
-function setBit(value: number, bit: number): number {
-  return value | bit
-}
-
-function clearBit(value: number, bit: number): number {
-  return value & ~bit
+export const wasTracked = (dep: Dep): boolean => (dep.w & trackOpBit) > 0
+
+export const newTracked = (dep: Dep): boolean => (dep.n & trackOpBit) > 0
+
+export const initDepMarkers = ({ deps }: ReactiveEffect) => {
+  if (deps.length) {
+    for (let i = 0; i < deps.length; i++) {
+      deps[i].w |= trackOpBit // set was tracked
+    }
+  }
+}
+
+export const finalizeDepMarkers = (effect: ReactiveEffect) => {
+  const { deps } = effect
+  if (deps.length) {
+    let ptr = 0
+    for (let i = 0; i < deps.length; i++) {
+      const dep = deps[i]
+      if (wasTracked(dep) && !newTracked(dep)) {
+        dep.delete(effect)
+      } else {
+        deps[ptr++] = dep
+      }
+      // clear bits
+      dep.w &= ~trackOpBit
+      dep.n &= ~trackOpBit
+    }
+    deps.length = ptr
+  }
 }
index 670b6b340c5736d96acdc52c2fb2092262f9e4f7..3a7271427022ab74e9420789fa1d22a0f7eff91a 100644 (file)
@@ -4,10 +4,9 @@ import { EffectScope, recordEffectScope } from './effectScope'
 import {
   createDep,
   Dep,
+  finalizeDepMarkers,
+  initDepMarkers,
   newTracked,
-  resetTracked,
-  setNewTracked,
-  setWasTracked,
   wasTracked
 } from './Dep'
 
@@ -18,6 +17,18 @@ import {
 type KeyToDepMap = Map<any, Dep>
 const targetMap = new WeakMap<any, KeyToDepMap>()
 
+// The number of effects currently being tracked recursively.
+let effectTrackDepth = 0
+
+export let trackOpBit = 1
+
+/**
+ * The bitwise track markers support at most 30 levels op recursion.
+ * This value is chosen to enable modern JS engines to use a SMI on all platforms.
+ * When recursion depth is greater, fall back to using a full cleanup.
+ */
+const maxMarkerBits = 30
+
 export type EffectScheduler = () => void
 
 export type DebuggerEvent = {
@@ -38,6 +49,7 @@ let activeEffect: ReactiveEffect | undefined
 
 export const ITERATE_KEY = Symbol(__DEV__ ? 'iterate' : '')
 export const MAP_KEY_ITERATE_KEY = Symbol(__DEV__ ? 'Map key iterate' : '')
+
 export class ReactiveEffect<T = any> {
   active = true
   deps: Dep[] = []
@@ -68,19 +80,21 @@ export class ReactiveEffect<T = any> {
         effectStack.push((activeEffect = this))
         enableTracking()
 
-        effectTrackDepth++
+        trackOpBit = 1 << ++effectTrackDepth
 
         if (effectTrackDepth <= maxMarkerBits) {
-          this.initDepMarkers()
+          initDepMarkers(this)
         } else {
-          this.cleanup()
+          cleanupEffect(this)
         }
         return this.fn()
       } finally {
         if (effectTrackDepth <= maxMarkerBits) {
-          this.finalizeDepMarkers()
+          finalizeDepMarkers(this)
         }
-        effectTrackDepth--
+
+        trackOpBit = 1 << --effectTrackDepth
+
         resetTracking()
         effectStack.pop()
         const n = effectStack.length
@@ -89,45 +103,9 @@ export class ReactiveEffect<T = any> {
     }
   }
 
-  initDepMarkers() {
-    const { deps } = this
-    if (deps.length) {
-      for (let i = 0; i < deps.length; i++) {
-        setWasTracked(deps[i])
-      }
-    }
-  }
-
-  finalizeDepMarkers() {
-    const { deps } = this
-    if (deps.length) {
-      let ptr = 0
-      for (let i = 0; i < deps.length; i++) {
-        const dep = deps[i]
-        if (wasTracked(dep) && !newTracked(dep)) {
-          dep.delete(this)
-        } else {
-          deps[ptr++] = dep
-        }
-        resetTracked(dep)
-      }
-      deps.length = ptr
-    }
-  }
-
-  cleanup() {
-    const { deps } = this
-    if (deps.length) {
-      for (let i = 0; i < deps.length; i++) {
-        deps[i].delete(this)
-      }
-      deps.length = 0
-    }
-  }
-
   stop() {
     if (this.active) {
-      this.cleanup()
+      cleanupEffect(this)
       if (this.onStop) {
         this.onStop()
       }
@@ -136,18 +114,14 @@ export class ReactiveEffect<T = any> {
   }
 }
 
-// The number of effects currently being tracked recursively.
-let effectTrackDepth = 0
-
-/**
- * The bitwise track markers support at most 30 levels op recursion.
- * This value is chosen to enable modern JS engines to use a SMI on all platforms.
- * When recursion depth is greater, fall back to using a full cleanup.
- */
-const maxMarkerBits = 30
-
-export function getTrackOpBit(): number {
-  return 1 << effectTrackDepth
+function cleanupEffect(effect: ReactiveEffect) {
+  const { deps } = effect
+  if (deps.length) {
+    for (let i = 0; i < deps.length; i++) {
+      deps[i].delete(effect)
+    }
+    deps.length = 0
+  }
 }
 
 export interface ReactiveEffectOptions {
@@ -218,8 +192,7 @@ export function track(target: object, type: TrackOpTypes, key: unknown) {
   }
   let dep = depsMap.get(key)
   if (!dep) {
-    dep = createDep()
-    depsMap.set(key, dep)
+    depsMap.set(key, (dep = createDep()))
   }
 
   const eventInfo = __DEV__
@@ -240,7 +213,7 @@ export function trackEffects(
   let shouldTrack = false
   if (effectTrackDepth <= maxMarkerBits) {
     if (!newTracked(dep)) {
-      setNewTracked(dep)
+      dep.n |= trackOpBit // set newly tracked
       shouldTrack = !wasTracked(dep)
     }
   } else {
index b879ed1b179839455de7657a5e2771b0396a3b13..e021c761dea4ce78ffe605277d62eb8c6e6c2103 100644 (file)
@@ -1395,33 +1395,28 @@ function baseCreateRenderer(
     isSVG,
     optimized
   ) => {
-    const componentUpdateFn = function(this: ReactiveEffect) {
+    const componentUpdateFn = () => {
       if (!instance.isMounted) {
         let vnodeHook: VNodeHook | null | undefined
         const { el, props } = initialVNode
         const { bm, m, parent } = instance
 
-        try {
-          // Disallow component effect recursion during pre-lifecycle hooks.
-          this.allowRecurse = false
-
-          // beforeMount hook
-          if (bm) {
-            invokeArrayFns(bm)
-          }
-          // onVnodeBeforeMount
-          if ((vnodeHook = props && props.onVnodeBeforeMount)) {
-            invokeVNodeHook(vnodeHook, parent, initialVNode)
-          }
-          if (
-            __COMPAT__ &&
-            isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
-          ) {
-            instance.emit('hook:beforeMount')
-          }
-        } finally {
-          this.allowRecurse = true
+        effect.allowRecurse = false
+        // beforeMount hook
+        if (bm) {
+          invokeArrayFns(bm)
+        }
+        // onVnodeBeforeMount
+        if ((vnodeHook = props && props.onVnodeBeforeMount)) {
+          invokeVNodeHook(vnodeHook, parent, initialVNode)
+        }
+        if (
+          __COMPAT__ &&
+          isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
+        ) {
+          instance.emit('hook:beforeMount')
         }
+        effect.allowRecurse = true
 
         if (el && hydrateNode) {
           // vnode has adopted host node - perform hydration instead of mount.
@@ -1547,27 +1542,23 @@ function baseCreateRenderer(
           next = vnode
         }
 
-        try {
-          // Disallow component effect recursion during pre-lifecycle hooks.
-          this.allowRecurse = false
-
-          // beforeUpdate hook
-          if (bu) {
-            invokeArrayFns(bu)
-          }
-          // onVnodeBeforeUpdate
-          if ((vnodeHook = next.props && next.props.onVnodeBeforeUpdate)) {
-            invokeVNodeHook(vnodeHook, parent, next, vnode)
-          }
-          if (
-            __COMPAT__ &&
-            isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
-          ) {
-            instance.emit('hook:beforeUpdate')
-          }
-        } finally {
-          this.allowRecurse = true
+        // Disallow component effect recursion during pre-lifecycle hooks.
+        effect.allowRecurse = false
+        // beforeUpdate hook
+        if (bu) {
+          invokeArrayFns(bu)
+        }
+        // onVnodeBeforeUpdate
+        if ((vnodeHook = next.props && next.props.onVnodeBeforeUpdate)) {
+          invokeVNodeHook(vnodeHook, parent, next, vnode)
+        }
+        if (
+          __COMPAT__ &&
+          isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
+        ) {
+          instance.emit('hook:beforeUpdate')
         }
+        effect.allowRecurse = true
 
         // render
         if (__DEV__) {