Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce async support for getHandler #183

Merged
merged 1 commit into from
Jul 14, 2016

Conversation

trentmwillis
Copy link
Contributor

@trentmwillis trentmwillis commented May 5, 2016

READY FOR REVIEW

In order to support lazy-loading, router.js should not assume handlers returned from getHandler will be present synchronously. This PR introduces support for loading handlers asynchronously by returning a Promise from the getHandler function.

A common response to this idea is why not load handlers upfront? The reason to avoid loading handlers upfront is that they have the potential of being stateful and dependent on other constructs. This introduces a dependency tree that also must be loaded upfront with the handler, thus potentially negating the benefit of lazy loading.

This implementation reuses all existing tests that defined a getHandler method and has them passing while returning a Promise-based handler instead. One callout here is that intermediateTransitionTo passes under the assumption that it is used to transition into a synchronously loaded route.

TODO:

  • Rebase ontop of Introduce getSerializer option #182
  • Simplify and make changes backwards-compatible
  • Audit tests to make sure everything is covered
  • Add documentation and clean up where appropriate
  • Squash commits

@trentmwillis trentmwillis force-pushed the get-handler-async branch 2 times, most recently from 6462567 to ecb3051 Compare May 20, 2016 23:34
@trentmwillis trentmwillis force-pushed the get-handler-async branch 2 times, most recently from 462ca5e to 5ba7c53 Compare July 11, 2016 23:29
@trentmwillis trentmwillis changed the title [WIP] Introduce async support for getHandler [Ready-For-Review] Introduce async support for getHandler Jul 11, 2016
@trentmwillis trentmwillis changed the title [Ready-For-Review] Introduce async support for getHandler Introduce async support for getHandler Jul 11, 2016
@rwjblue
Copy link
Collaborator

rwjblue commented Jul 11, 2016

It would be great if @machty had a chance to review (though not a blocker per-se).


return Promise.resolve(this.handlerPromise, this.promiseLabel("Start handler"))
.then(function(handler) {
return Promise.resolve(handler)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this nesting needed? I could be missing something, but I would think this would work:

return Promise.resolve(this.handlerPromise, this.promiseLabel("Start handler"))
    .then(checkForAbort, null, self.promiseLabel("Check for abort"))
    .then(beforeModel, null, self.promiseLabel("Before model"))
    .then(checkForAbort, null, self.promiseLabel("Check if aborted during 'beforeModel' hook"))
    .then(model, null, self.promiseLabel("Model"))
    .then(checkForAbort, null, self.promiseLabel("Check if aborted in 'model' hook"))
    .then(afterModel, null, self.promiseLabel("After model"))
    .then(checkForAbort, null, self.promiseLabel("Check if aborted in 'afterModel' hook"))
    .then(becomeResolved, null, self.promiseLabel("Become resolved"));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we can do that, the one issue with that approach (and the reason the code is this way) is if we have an error early on in the chain (for example when checking inaccessibleByURL), then we have to propagate it through the whole chain which is annoying.

Determines if an object is Promise by checking if it is "thenable".
**/
export function isPromise(obj) {
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you tweak to:

return ((typeof obj === 'object' && obj !== null) || typeof obj === 'function') && typeof obj.then === 'function';

We would prefer to only do the comparison to null (instead of !!obj) when it is an object.

@rwjblue
Copy link
Collaborator

rwjblue commented Jul 14, 2016

Just a few small nit-pick things, but this LGTM. Can you update those things and squash?

Determines if an object is Promise by checking if it is "thenable".
**/
export function isPromise(obj) {
return ((typeof obj === 'object' && typeof obj !== null) || typeof obj === 'function') && typeof obj.then === 'function';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should just be obj !== null, not typeof obj !== null

getHandler can now return a Promise for handlers that need to be
fetched asynchronously. Two notable differences from the sync
case are inaccessibleByURL and intermediateTransitionTo.

inaccessibleByURL will now error after going through a loading
state since we need to load the handler before being able to
determine accessibility.

intermediateTransitionTo will assume that the handler is available
synchronously as it should be used for error and loading substates.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants