浏览代码

debounce for render queue

Adam Shaw 7 年之前
父节点
当前提交
d0cf8fb545
共有 2 个文件被更改,包括 61 次插入30 次删除
  1. 56 18
      src/Calendar.ts
  2. 5 12
      src/util/misc.ts

+ 56 - 18
src/Calendar.ts

@@ -75,7 +75,11 @@ export default class Calendar {
   state: CalendarState
   actionQueue = []
   isReducing: boolean = false
+
   renderingPauseDepth: number = 0
+  rerenderFlags: RenderForceFlags
+  buildDelayedRerender: any
+  delayedRerender: any
 
 
   constructor(el: HTMLElement, overrides: OptionsInput) {
@@ -87,6 +91,7 @@ export default class Calendar {
 
     this.buildDateEnv = reselector(buildDateEnv)
     this.buildTheme = reselector(buildTheme)
+    this.buildDelayedRerender = reselector(buildDelayedRerender)
 
     this.handleOptions(this.optionsManager.computed)
     this.constructed()
@@ -290,7 +295,7 @@ export default class Calendar {
   }
 
 
-  // Dispatcher / Render Queue
+  // Dispatcher
   // -----------------------------------------------------------------------------------------------------------------
 
 
@@ -354,31 +359,51 @@ export default class Calendar {
         this.publiclyTrigger('loading', [ false, this.view ])
       }
 
-      this.tryRerender()
+      this.requestRerender()
     }
   }
 
 
-  pauseRendering() {
-    this.renderingPauseDepth++
+  reduce(state: CalendarState, action: object, calendar: Calendar): CalendarState {
+    return reduce(state, action, calendar)
   }
 
 
-  resumeRendering() {
-    this.renderingPauseDepth--
-    this.tryRerender()
+  // Render Queue
+  // -----------------------------------------------------------------------------------------------------------------
+
+
+  requestRerender(forces: RenderForceFlags = {}) {
+    if (forces === true || !this.rerenderFlags) {
+      this.rerenderFlags = forces // true, or the first object
+    } else if (this.rerenderFlags) {
+      assignTo(this.rerenderFlags, forces) // merge the objects
+    }
+
+    this.delayedRerender()
   }
 
 
-  tryRerender(forces?) {
-    if (!this.renderingPauseDepth && this.isRendered) {
-      this._render(forces)
+  tryRerender() {
+    if (
+      !this.renderingPauseDepth && // not paused
+      this.isRendered && // must be currently rendered
+      this.rerenderFlags // indicates that a rerender was requested
+    ) {
+      this._render(this.rerenderFlags)
+      this.rerenderFlags = null
     }
   }
 
 
-  reduce(state: CalendarState, action: object, calendar: Calendar): CalendarState {
-    return reduce(state, action, calendar)
+  pauseRendering() {
+    this.renderingPauseDepth++
+  }
+
+
+  resumeRendering() {
+    this.renderingPauseDepth--
+    this.requestRerender()
   }
 
 
@@ -425,14 +450,15 @@ export default class Calendar {
     }
 
     this.viewsByType = {}
-    this.tryRerender(true) // force=true
+    this.requestRerender(true) // force=true
   }
 
 
   handleOptions(options) {
     this.defaultAllDayEventDuration = createDuration(options.defaultAllDayEventDuration)
     this.defaultTimedEventDuration = createDuration(options.defaultTimedEventDuration)
-
+    this.delayedRerender = this.buildDelayedRerender(options.eventRenderWait) // TODO: rename settings
+    this.theme = this.buildTheme(options)
     this.dateEnv = this.buildDateEnv(
       options.locale,
       options.timezone,
@@ -441,8 +467,6 @@ export default class Calendar {
       options.weekLabel
     )
 
-    this.theme = this.buildTheme(options)
-
     this.viewSpecManager.clearCache()
   }
 
@@ -979,7 +1003,7 @@ export default class Calendar {
 
 
   rerenderEvents() { // API method. destroys old events if previously rendered.
-    this.tryRerender({ events: true }) // TODO: test this
+    this.requestRerender({ events: true }) // TODO: test this
   }
 
 
@@ -1023,7 +1047,7 @@ export default class Calendar {
 
 
   // Public Event Sources API
-  // ------------------------------------------------------------------------------------
+  // -----------------------------------------------------------------------------------------------------------------
 
 
   getEventSources(): EventSource {
@@ -1062,6 +1086,9 @@ EmitterMixin.mixIntoObj(Calendar) // for global registry
 EmitterMixin.mixInto(Calendar)
 
 
+// for reselectors
+// -----------------------------------------------------------------------------------------------------------------
+
 
 function buildDateEnv(locale, timezone, firstDay, weekNumberCalculation, weekLabel) {
   return new DateEnv({
@@ -1079,3 +1106,14 @@ function buildTheme(calendarOptions) {
   let themeClass = getThemeSystemClass(calendarOptions.themeSystem || calendarOptions.theme)
   return new themeClass(calendarOptions)
 }
+
+
+function buildDelayedRerender(this: Calendar, wait) {
+  let func = this.tryRerender.bind(this)
+
+  if (wait != null) {
+    func = debounce(func, wait)
+  }
+
+  return func
+}

+ 5 - 12
src/util/misc.ts

@@ -348,7 +348,7 @@ export function firstDefined(...args) {
 // N milliseconds. If `immediate` is passed, trigger the function on the
 // leading edge, instead of the trailing.
 // https://github.com/jashkenas/underscore/blob/1.6.0/underscore.js#L714
-export function debounce(func, wait, immediate= false) {
+export function debounce(func, wait) {
   let timeout
   let args
   let context
@@ -356,30 +356,23 @@ export function debounce(func, wait, immediate= false) {
   let result
 
   let later = function() {
-    let last = +new Date() - timestamp
+    let last = new Date().valueOf() - timestamp
     if (last < wait) {
       timeout = setTimeout(later, wait - last)
     } else {
       timeout = null
-      if (!immediate) {
-        result = func.apply(context, args)
-        context = args = null
-      }
+      result = func.apply(context, args)
+      context = args = null
     }
   }
 
   return function() {
     context = this
     args = arguments
-    timestamp = +new Date()
-    let callNow = immediate && !timeout
+    timestamp = new Date().valueOf()
     if (!timeout) {
       timeout = setTimeout(later, wait)
     }
-    if (callNow) {
-      result = func.apply(context, args)
-      context = args = null
-    }
     return result
   }
 }