]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
perf(reactivity): avoid triggering re-render if computed value did not change
authorEvan You <yyx990803@gmail.com>
Wed, 7 Jul 2021 02:01:59 +0000 (22:01 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 16 Jul 2021 18:30:49 +0000 (14:30 -0400)
packages/reactivity/src/computed.ts
packages/reactivity/src/index.ts
packages/runtime-core/src/scheduler.ts

index 396e50ecdb068d52b3f28d096e4d484fa92ed6e7..0fe19191eb77e4fc4affc190d1eac41ebfda23b6 100644 (file)
@@ -5,6 +5,7 @@ import { ReactiveFlags, toRaw } from './reactive'
 
 export interface ComputedRef<T = any> extends WritableComputedRef<T> {
   readonly value: T
+  defer?: (fn: () => void) => void
 }
 
 export interface WritableComputedRef<T> extends Ref<T> {
@@ -19,6 +20,16 @@ export interface WritableComputedOptions<T> {
   set: ComputedSetter<T>
 }
 
+type ComputedScheduler = (fn: () => void) => void
+let scheduler: ComputedScheduler | undefined
+
+/**
+ * Set a scheduler for deferring computed computations
+ */
+export const setComputedScheduler = (s: ComputedScheduler | undefined) => {
+  scheduler = s
+}
+
 class ComputedRefImpl<T> {
   public dep?: Set<ReactiveEffect> = undefined
 
@@ -35,10 +46,34 @@ class ComputedRefImpl<T> {
     private readonly _setter: ComputedSetter<T>,
     isReadonly: boolean
   ) {
+    let deferFn: () => void
+    let scheduled = false
     this.effect = new ReactiveEffect(getter, () => {
       if (!this._dirty) {
         this._dirty = true
-        triggerRefValue(this)
+        if (scheduler) {
+          if (!scheduled) {
+            scheduled = true
+            scheduler(
+              deferFn ||
+                (deferFn = () => {
+                  scheduled = false
+                  if (this._dirty) {
+                    this._dirty = false
+                    const newValue = this.effect.run()!
+                    if (this._value !== newValue) {
+                      this._value = newValue
+                      triggerRefValue(this)
+                    }
+                  } else {
+                    triggerRefValue(this)
+                  }
+                })
+            )
+          }
+        } else {
+          triggerRefValue(this)
+        }
       }
     })
     this[ReactiveFlags.IS_READONLY] = isReadonly
index d86f0bde882cfefe2ecf1f7afebd6d3249b2e78d..3d4b05730a5182984642ca815e7bbd239b72f826 100644 (file)
@@ -30,6 +30,7 @@ export {
 } from './reactive'
 export {
   computed,
+  setComputedScheduler,
   ComputedRef,
   WritableComputedRef,
   WritableComputedOptions,
index 3c79a3be210ca0c823fbbe963a0544086aad2f6c..e5ef4e849c7d2e11fad7d4f34c53e05b74c8a88d 100644 (file)
@@ -2,6 +2,10 @@ import { ErrorCodes, callWithErrorHandling } from './errorHandling'
 import { isArray } from '@vue/shared'
 import { ComponentInternalInstance, getComponentName } from './component'
 import { warn } from './warning'
+import { setComputedScheduler } from '@vue/reactivity'
+
+// set scheduler for computed
+setComputedScheduler(queueJob)
 
 export interface SchedulerJob extends Function {
   id?: number