瀏覽代碼

finish doing render memoization

Adam Shaw 7 年之前
父節點
當前提交
0164d198ad
共有 6 個文件被更改,包括 112 次插入38 次删除
  1. 4 1
      src/CalendarComponent.ts
  2. 15 6
      src/Toolbar.ts
  3. 26 10
      src/View.ts
  4. 27 8
      src/agenda/TimeGrid.ts
  5. 23 7
      src/basic/DayGrid.ts
  6. 17 6
      src/basic/DayTile.ts

+ 4 - 1
src/CalendarComponent.ts

@@ -15,6 +15,7 @@ import reselector from './util/reselector'
 import { computeHeightAndMargins } from './util/dom-geom'
 import { createFormatter } from './datelib/formatting'
 import { diffWholeDays } from './datelib/marker'
+import { memoizeRendering } from './component/memoized-rendering'
 
 export interface CalendarComponentProps {
   viewSpec: ViewSpec
@@ -43,6 +44,8 @@ export default class CalendarComponent extends Component<CalendarComponentProps>
   isHeightAuto: boolean
   viewHeight: number
 
+  private _renderToolbars = memoizeRendering(this.renderToolbars)
+
 
   constructor(context: ComponentContext, el: HTMLElement) {
     super(context)
@@ -102,7 +105,7 @@ export default class CalendarComponent extends Component<CalendarComponentProps>
     this.freezeHeight()
 
     let title = this.computeTitle(props.dateProfile, props.viewSpec.options)
-    this.subrender('renderToolbars', [ props.viewSpec, props.dateProfile, props.dateProfileGenerator, title ])
+    this._renderToolbars(props.viewSpec, props.dateProfile, props.dateProfileGenerator, title)
     this.renderView(props, title)
 
     this.updateRootSize()

+ 15 - 6
src/Toolbar.ts

@@ -2,6 +2,7 @@ import { htmlEscape } from './util/html'
 import { htmlToElement, appendToElement, findElements, createElement, removeElement } from './util/dom-manip'
 import Component, { ComponentContext } from './component/Component'
 import { ViewSpec } from './structs/view-spec'
+import { memoizeRendering } from './component/memoized-rendering'
 
 /* Toolbar with buttons and title
 ----------------------------------------------------------------------------------------------------------------------*/
@@ -20,6 +21,13 @@ export default class Toolbar extends Component<ToolbarRenderProps> {
   el: HTMLElement
   viewsWithButtons: any
 
+  private _renderLayout = memoizeRendering(this.renderLayout, this.unrenderLayout)
+  private _updateTitle = memoizeRendering(this.updateTitle, null, [ this._renderLayout ])
+  private _updateActiveButton = memoizeRendering(this.updateActiveButton, null, [ this._renderLayout ])
+  private _updateToday = memoizeRendering(this.updateToday, null, [ this._renderLayout ])
+  private _updatePrev = memoizeRendering(this.updatePrev, null, [ this._renderLayout ])
+  private _updateNext = memoizeRendering(this.updateNext, null, [ this._renderLayout ])
+
 
   constructor(context: ComponentContext, extraClassName) {
     super(context)
@@ -31,17 +39,18 @@ export default class Toolbar extends Component<ToolbarRenderProps> {
   destroy() {
     super.destroy()
 
+    this._renderLayout.unrender() // should unrender everything else
     removeElement(this.el)
   }
 
 
   render(props: ToolbarRenderProps) {
-    let layoutId = this.subrender('renderLayout', [ props.layout ], 'unrenderLayout')
-    this.subrender('updateTitle', [ props.title, layoutId ])
-    this.subrender('updateActiveButton', [ props.activeButton, layoutId ])
-    this.subrender('updateToday', [ props.isTodayEnabled, layoutId ])
-    this.subrender('updatePrev', [ props.isPrevEnabled, layoutId ])
-    this.subrender('updateNext', [ props.isNextEnabled, layoutId ])
+    this._renderLayout(props.layout)
+    this._updateTitle(props.title)
+    this._updateActiveButton(props.activeButton)
+    this._updateToday(props.isTodayEnabled)
+    this._updatePrev(props.isPrevEnabled)
+    this._updateNext(props.isNextEnabled)
   }
 
 

+ 26 - 10
src/View.ts

@@ -12,6 +12,7 @@ import { EventStore } from './structs/event-store'
 import { EventUiHash, sliceEventStore, EventRenderRange } from './component/event-rendering'
 import { DateSpan } from './structs/date-span'
 import { EventInteractionUiState } from './interactions/event-interaction-state'
+import { memoizeRendering } from './component/memoized-rendering'
 
 export interface ViewProps {
   dateProfile: DateProfile
@@ -57,6 +58,14 @@ export default abstract class View extends DateComponent<ViewProps> {
   nowIndicatorTimeoutID: any // for refresh timing of now indicator
   nowIndicatorIntervalID: any // "
 
+  private _renderDates = memoizeRendering(this.__renderDates, this.__unrenderDates)
+  private _renderBusinessHours = memoizeRendering(this.renderBusinessHours, this.unrenderBusinessHours, [ this._renderDates ])
+  private _renderDateSelectionState = memoizeRendering(this.renderDateSelectionState, this.unrenderDateSelection, [ this._renderDates ])
+  private _renderEvents = memoizeRendering(this.__renderEvents, this.unrenderEvents, [ this._renderDates ])
+  private _renderEventSelection = memoizeRendering(this.renderEventSelection, this.unrenderEventSelection, [ this._renderEvents ])
+  private _renderEventDragState = memoizeRendering(this.renderEventDragState, this.unrenderEventDragState, [ this._renderDates ])
+  private _renderEventResizeState = memoizeRendering(this.renderEventResizeState, this.unrenderEventResizeState, [ this._renderDates ])
+
 
   constructor(context: ComponentContext, viewSpec: ViewSpec, dateProfileGenerator: DateProfileGenerator, parentEl: HTMLElement) {
     super(
@@ -112,13 +121,20 @@ export default abstract class View extends DateComponent<ViewProps> {
 
 
   render(props: ViewProps) {
-    let dateId = this.subrender('_renderDates', [ props.dateProfile ], '_unrenderDates')
-    this.subrender('renderBusinessHours', [ props.businessHours, props.dateProfile, dateId ], 'unrenderBusinessHours')
-    this.subrender('renderDateSelectionState', [ props.dateSelection, dateId ], 'unrenderDateSelection')
-    let evId = this.subrender('_renderEvents', [ props.eventStore, props.eventUis, dateId ], 'unrenderEvents')
-    this.subrender('renderEventSelection', [ props.eventSelection, evId ], 'unrenderEventSelection')
-    this.subrender('renderEventDragState', [ props.eventDrag, dateId ], 'unrenderEventDragState')
-    this.subrender('renderEventResizeState', [ props.eventResize, dateId ], 'unrenderEventResizeState')
+    this._renderDates(props.dateProfile)
+    this._renderBusinessHours(props.businessHours)
+    this._renderDateSelectionState(props.dateSelection)
+    this._renderEvents(props.eventStore, props.eventUis)
+    this._renderEventSelection(props.eventSelection)
+    this._renderEventDragState(props.eventDrag)
+    this._renderEventResizeState(props.eventResize)
+  }
+
+
+  destroy() {
+    super.destroy()
+
+    this._renderDates.unrender() // should unrender everything else
   }
 
 
@@ -167,14 +183,14 @@ export default abstract class View extends DateComponent<ViewProps> {
   // -----------------------------------------------------------------------------------------------------------------
 
 
-  _renderDates(dateProfile: DateProfile) {
+  __renderDates(dateProfile: DateProfile) {
     this.renderDates(dateProfile)
     this.addScroll({ isDateInit: true })
     this.startNowIndicator() // shouldn't render yet because updateSize will be called soon
     this.isDateSizeDirty = true
   }
 
-  _unrenderDates() {
+  __unrenderDates() {
     this.stopNowIndicator()
     this.unrenderDates()
   }
@@ -186,7 +202,7 @@ export default abstract class View extends DateComponent<ViewProps> {
   // Event Rendering
   // -----------------------------------------------------------------------------------------------------------------
 
-  _renderEvents(eventStore: EventStore, eventUis: EventUiHash) {
+  __renderEvents(eventStore: EventStore, eventUis: EventUiHash) {
     this.isEventSizeDirty = true
     this.renderEvents(eventStore, eventUis)
   }

+ 27 - 8
src/agenda/TimeGrid.ts

@@ -11,6 +11,7 @@ import { ComponentContext } from '../component/Component'
 import DateComponent, { Seg, EventSegUiInteractionState } from '../component/DateComponent'
 import DayBgRow from '../basic/DayBgRow'
 import { DateProfile } from '../DateProfileGenerator'
+import { memoizeRendering } from '../component/memoized-rendering'
 
 
 /* A component that renders one or more columns of vertical time slots
@@ -86,6 +87,15 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
   highlightContainerEls: HTMLElement[]
   businessContainerEls: HTMLElement[]
 
+  private _renderSlats = memoizeRendering(this.renderSlats)
+  private _renderColumns = memoizeRendering(this.renderColumns, this.unrenderColumns)
+  private _renderBusinessHourSegs = memoizeRendering(this.renderBusinessHourSegs, this.unrenderBusinessHours, [ this._renderColumns ])
+  private _renderDateSelectionSegs = memoizeRendering(this.renderDateSelectionSegs, this.unrenderDateSelection, [ this._renderColumns ])
+  private _renderEventSegs = memoizeRendering(this.renderEventSegs, this.unrenderEvents, [ this._renderColumns ])
+  private _renderEventSelection = memoizeRendering(this.renderEventSelection, this.unrenderEventSelection, [ this._renderEventSegs ])
+  private _renderEventDragSegs = memoizeRendering(this.renderEventDragSegs, this.unrenderEventDragSegs, [ this._renderColumns ])
+  private _renderEventResizeSegs = memoizeRendering(this.renderEventResizeSegs, this.unrenderEventResizeSegs, [ this._renderColumns ])
+
 
   constructor(context: ComponentContext, el: HTMLElement, renderProps: RenderProps) {
     super(context, el)
@@ -182,14 +192,23 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
     let cells = props.cells
     this.colCnt = cells.length
 
-    this.subrender('renderSlats', [ props.dateProfile ])
-    let dateId = this.subrender('renderColumns', [ props.cells, props.dateProfile ], 'unrenderColumns')
-    this.subrender('renderBusinessHourSegs', [ props.businessHourSegs, props.dateProfile, dateId ], 'unrenderBusinessHours')
-    this.subrender('renderDateSelectionSegs', [ props.dateSelectionSegs, dateId ], 'unrenderDateSelection')
-    let evId = this.subrender('renderEventSegs', [ props.eventSegs, dateId ], 'unrenderEvents')
-    this.subrender('renderEventSelection', [ props.eventSelection, evId ], 'unrenderEventSelection')
-    this.subrender('renderEventDragSegs', [ props.eventDrag, dateId ], 'unrenderEventDragSegs')
-    this.subrender('renderEventResizeSegs', [ props.eventResize, dateId ], 'unrenderEventResizeSegs')
+    this._renderSlats(props.dateProfile)
+    this._renderColumns(props.cells, props.dateProfile)
+    this._renderBusinessHourSegs(props.businessHourSegs)
+    this._renderDateSelectionSegs(props.dateSelectionSegs)
+    this._renderEventSegs(props.eventSegs)
+    this._renderEventSelection(props.eventSelection)
+    this._renderEventDragSegs(props.eventDrag)
+    this._renderEventResizeSegs(props.eventResize)
+  }
+
+
+  destroy() {
+    super.destroy()
+
+    // should unrender everything else too
+    this._renderSlats.unrender()
+    this._renderColumns.unrender()
   }
 
 

+ 23 - 7
src/basic/DayGrid.ts

@@ -22,6 +22,7 @@ import { EventRenderRange } from '../component/event-rendering'
 import { buildGotoAnchorHtml, getDayClasses } from '../component/date-rendering'
 import DayBgRow from './DayBgRow'
 import { DateProfile } from '../DateProfileGenerator'
+import { memoizeRendering } from '../component/memoized-rendering'
 
 const DAY_NUM_FORMAT = createFormatter({ day: 'numeric' })
 const WEEK_NUM_FORMAT = createFormatter({ week: 'numeric' })
@@ -84,6 +85,14 @@ export default class DayGrid extends DateComponentProps<DayGridProps> {
   segPopover: Popover // the Popover that holds events that can't fit in a cell. null when not visible
   segPopoverTile: DayTile
 
+  private _renderCells = memoizeRendering(this.renderCells, this.unrenderCells)
+  private _renderBusinessHourSegs = memoizeRendering(this.renderBusinessHourSegs, this.unrenderBusinessHours, [ this._renderCells ])
+  private _renderDateSelectionSegs = memoizeRendering(this.renderDateSelectionSegs, this.unrenderDateSelection, [ this._renderCells ])
+  private _renderEventSegs = memoizeRendering(this.renderEventSegs, this.unrenderEvents, [ this._renderCells ])
+  private _renderEventSelection = memoizeRendering(this.renderEventSelection, this.unrenderEventSelection, [ this._renderCells ])
+  private _renderEventDragSegs = memoizeRendering(this.renderEventDragSegs, this.unrenderEventDragSegs, [ this._renderCells ])
+  private _renderEventResizeSegs = memoizeRendering(this.renderEventResizeSegs, this.unrenderEventResizeSegs, [ this._renderCells ])
+
 
   constructor(context, el, renderProps: RenderProps) {
     super(context, el)
@@ -101,13 +110,13 @@ export default class DayGrid extends DateComponentProps<DayGridProps> {
     this.rowCnt = cells.length
     this.colCnt = cells[0].length
 
-    let dateId = this.subrender('renderCells', [ props.cells, props.isRigid ], 'unrenderCells')
-    this.subrender('renderBusinessHourSegs', [ props.businessHourSegs, props.dateProfile, dateId ], 'unrenderBusinessHours')
-    this.subrender('renderDateSelectionSegs', [ props.dateSelectionSegs, dateId ], 'unrenderDateSelection')
-    let evId = this.subrender('renderEventSegs', [ props.eventSegs, dateId ], 'unrenderEvents')
-    this.subrender('renderEventSelection', [ props.eventSelection, evId ], 'unrenderEventSelection')
-    this.subrender('renderEventDragSegs', [ props.eventDrag, dateId ], 'unrenderEventDragSegs')
-    this.subrender('renderEventResizeSegs', [ props.eventResize, dateId ], 'unrenderEventResizeSegs')
+    this._renderCells(cells, props.isRigid)
+    this._renderBusinessHourSegs(props.businessHourSegs)
+    this._renderDateSelectionSegs(props.dateSelectionSegs)
+    this._renderEventSegs(props.eventSegs)
+    this._renderEventSelection(props.eventSelection)
+    this._renderEventDragSegs(props.eventDrag)
+    this._renderEventResizeSegs(props.eventResize)
 
     if (this.segPopoverTile) {
       this.updateSegPopoverTile()
@@ -115,6 +124,13 @@ export default class DayGrid extends DateComponentProps<DayGridProps> {
   }
 
 
+  destroy() {
+    super.destroy()
+
+    this._renderCells.unrender() // will unrender everything else
+  }
+
+
   getCellRange(row, col) {
     let start = this.props.cells[row][col].date
     let end = addDays(start, 1)

+ 17 - 6
src/basic/DayTile.ts

@@ -10,6 +10,7 @@ import { addDays, DateMarker } from '../datelib/marker'
 import { removeElement } from '../util/dom-manip'
 import { ComponentContext } from '../component/Component'
 import { EventInstanceHash } from '../structs/event'
+import { memoizeRendering } from '../component/memoized-rendering'
 
 export interface DayTileProps {
   date: DateMarker
@@ -26,6 +27,11 @@ export default class DayTile extends DateComponent<DayTileProps> {
   height: number
   offsetTracker: OffsetTracker // TODO: abstraction for tracking dims of whole element rect
 
+  private _renderFrame = memoizeRendering(this.renderFrame)
+  private _renderEventSegs = memoizeRendering(this.renderEventSegs, this.unrenderEvents, [ this._renderFrame ])
+  private _renderEventSelection = memoizeRendering(this.renderEventSelection, this.unrenderEventSelection, [ this._renderEventSegs ])
+  private _renderEventDrag = memoizeRendering(this.renderEventDrag, this.unrenderEventDrag, [ this._renderFrame ])
+  private _renderEventResize = memoizeRendering(this.renderEventResize, this.unrenderEventResize, [ this._renderFrame ])
 
   constructor(context: ComponentContext, el: HTMLElement) {
     super(context, el)
@@ -33,13 +39,18 @@ export default class DayTile extends DateComponent<DayTileProps> {
     this.eventRenderer = new DayTileEventRenderer(this)
   }
 
-
   render(props: DayTileProps) {
-    let dateId = this.subrender('renderFrame', [ props.date ])
-    let evId = this.subrender('renderEventSegs', [ props.segs, dateId ], 'unrenderEvents')
-    this.subrender('renderEventSelection', [ props.eventSelection, evId ], 'unrenderEventSelection')
-    this.subrender('renderEventDrag', [ props.eventDragInstances, dateId ], 'unrenderEventDrag')
-    this.subrender('renderEventResize', [ props.eventResizeInstances, dateId ], 'unrenderEventResize')
+    this._renderFrame(props.date)
+    this._renderEventSegs(props.segs)
+    this._renderEventSelection(props.eventSelection)
+    this._renderEventDrag(props.eventDragInstances)
+    this._renderEventResize(props.eventResizeInstances)
+  }
+
+  destroy() {
+    super.destroy()
+
+    this._renderFrame.unrender() // should unrender everything else
   }
 
   renderFrame(date: DateMarker) {