diff --git a/src/application.ts b/src/application.ts index 123fd9b..499d9eb 100644 --- a/src/application.ts +++ b/src/application.ts @@ -25,6 +25,8 @@ import DynamicScope from './dynamic-scope'; import Environment from './environment'; import mainTemplate from './templates/main'; +function NOOP() {} + export interface ApplicationOptions { rootName: string; resolver: Resolver; @@ -50,17 +52,16 @@ export default class Application implements Owner { private _rootsIndex: number = 0; private _registry: Registry; private _container: Container; - private _renderResult: RenderResult; - private _afterRender: Option<() => void>; - /** Whether a re-render has been scheduled. */ - private _scheduled: Option> = null; private _initializers: Initializer[] = []; private _initialized = false; + private _rerender: () => void = NOOP; + private _afterRender: () => void = NOOP; + private _renderPromise: Option>; constructor(options: ApplicationOptions) { this.rootName = options.rootName; this.resolver = options.resolver; - this._scheduled = new Promise(resolve => { + this._renderPromise = new Promise(resolve => { this._afterRender = resolve; }); } @@ -138,13 +139,25 @@ export default class Application implements Owner { this.env.commit(); - let { _afterRender: afterRender } = this; + let renderResult = result.value; + + this.rerender = () => { + this.env.begin(); + renderResult.rerender(); + this.env.commit(); + this.didRender(); + }; + + this.didRender(); + } + + didRender(): void { + let { _afterRender } = this; - this._afterRender = null; - this._scheduled = null; - this._renderResult = result.value; + this._afterRender = NOOP; + this._renderPromise = null; - afterRender(); + _afterRender(); } renderComponent( @@ -156,24 +169,24 @@ export default class Application implements Owner { return this.scheduleRerender(); } - /** @hidden */ - rerender(): void { - this.env.begin(); - this._renderResult.rerender(); - this.env.commit(); - } - - /** @hidden */ scheduleRerender(): Promise { - if (this._scheduled) return this._scheduled; + let { _renderPromise } = this; - return this._scheduled = new Promise(resolve => { - requestAnimationFrame(() => { - this._scheduled = null; - this.rerender(); - resolve(); + if (_renderPromise === null) { + _renderPromise = this._renderPromise = new Promise(resolve =>{ + this._afterRender = resolve; }); - }); + + this._scheduleRerender(); + } + + return _renderPromise; + } + + _scheduleRerender(): void { + if (this._renderPromise !== null) { + requestAnimationFrame(this._rerender); + } } /** diff --git a/test/action-test.ts b/test/action-test.ts index 0800247..0afff6e 100644 --- a/test/action-test.ts +++ b/test/action-test.ts @@ -46,7 +46,7 @@ test('can curry arguments to actions', function(assert) { passedEvent = null; helloWorldComponent.name = "cruel world"; - app.rerender(); + app.scheduleRerender(); h1 = app.rootElement.querySelector('h1'); h1.onclick(fakeEvent); diff --git a/test/environment-test.ts b/test/environment-test.ts index c04843d..95cca82 100644 --- a/test/environment-test.ts +++ b/test/environment-test.ts @@ -64,7 +64,7 @@ test('can render a component with the component helper', function(assert) { assert.equal(app.rootElement.innerText, 'Hello Glimmer!'); - app.rerender(); + app.scheduleRerender(); assert.equal(app.rootElement.innerText, 'Hello Glimmer!'); }); @@ -95,7 +95,7 @@ test('can render a custom helper', function(assert) { assert.equal(app.rootElement.innerText, 'Hello Glimmer!'); - app.rerender(); + app.scheduleRerender(); assert.equal(app.rootElement.innerText, 'Hello Glimmer!'); }); @@ -114,7 +114,7 @@ test('can render a custom helper that takes args', function(assert) { assert.equal(app.rootElement.innerText, 'Hello Tom Dale!'); - app.rerender(); + app.scheduleRerender(); assert.equal(app.rootElement.innerText, 'Hello Tom Dale!'); });