-
Notifications
You must be signed in to change notification settings - Fork 13
Conversation
src/application.ts
Outdated
private _initializers: Initializer[] = []; | ||
private _initialized = false; | ||
|
||
constructor(options: ApplicationOptions) { | ||
this.rootName = options.rootName; | ||
this.resolver = options.resolver; | ||
this._scheduled = new Promise<void>(resolve => { | ||
this._afterRender = resolve; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what allows us to get rid of _rendered
.
84690ca
to
92111a4
Compare
return app.renderComponent('hello-world', containerElement).then(() => { | ||
assert.equal(containerElement.innerHTML, '<h1>Hello Glimmer!</h1>'); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add tests for rendering multiple components, rendering into tags with existing content (with or without nextSibling), etc?
92111a4
to
9d83e86
Compare
@chancancode Just added a bunch of tests. Let me know how this looks. |
I'm OK with this returning a promise, but:
|
@robbiepitts @tomdale Re: (2) the micro-optimization from Benedikt's slide isn't actually referring to this case (and it likely won't matter here). If we care about that, the right thing to do here is to check for We can do (1) though. Something like this would probably work: function NOOP() {}
class Application {
private rerender: () => void = NOOP;
private afterRender: () => void = NOOP;
private renderPromise: Option<Promise<void>>;
constructor() {
// ...
// This, or maintain the `rendered` flag, etc
this.renderPromise = new Promise<void>(resolve =>{
this.afterRender = resolve;
});
}
render() {
// ...
this.env.commit();
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 = NOOP;
this.renderPromise = null;
afterRender();
}
scheduleRerender(): Promise<void> {
let { renderPromise } = this;
if (renderPromise === null) {
renderPromise = this.renderPromise = new Promise<void>(resolve =>{
this.afterRender = resolve;
});
this._scheduleRerender();
}
return renderPromise;
}
// internal version used by @tracked, etc
_scheduleRerender() {
if (this.renderPromise !== null) {
requestAnimationFrame(this.rerender);
}
}
} Does that make sense? |
9d83e86
to
faa3ab6
Compare
Just updated this per @chancancode's revision. I feel like I'm missing something though. I'm not seeing a path that avoids the |
46acd0e
to
f907df6
Compare
My latest commit adds the promise-free path along with a couple boolean flags that seemed necessary to me. Essentially, |
Looks good to me! @krisselden might be able to comment on what patterns are good/bad performance-wise, but that could happen async and we don't need to block on that. @tomdale seems good to you? |
This looks good. My one request is that sooner rather than later we think generally about how we want to expose global rendering/lifecycle events. There are a number of things that are currently internal that people might want for testing, analytics, performance measuring, etc. I'd prefer to think about the problem holistically instead of accreting promise-based APIs for every use case that crops up. |
In order to test rendering (which is currently async) we needed to return a promise from
scheduleRerender
and by extensionrenderComponent
. What do y'all think about this?cc @chancancode @tomdale