This section describes some of the more advanced features of routers and the ability to handle complex asynchronous logic.
One, a word on promises
1. In the router of Ember, Ember uses a large number of promises concepts to handle asynchronous logic. In short, promises is an object that represents the final value. A promise can fulfill(successfully parse value) or reject (parse value fails).
2. The method of retrieving this final value or when promise reject is handled by Promise's then method. The then method accepts two optional callbacks, one for fulfillment and the other for rejection.
3. If promise executes, fulfillment handler is called and uses fulfilled value as the only parameter, if promise is rejected, rejection Handler is called and the reason for the rejection is reason for the rejection as its only parameter:
Example
var promise = fetchtheanswer ();p romise.then (fulfill, reject); function Fulfill (answer) { Console.log ("The answer is" + answer);} function reject (reason) { console.log ("couldn ' t get the answer! Reason: "+ Reason);}
4. Promises most of the power comes from the fact that they can be chained together to perform sequential asynchronous operations:
// Note:jquery AJAX methods return promises var usernamespromise = Ember.$.getjson ('/usernames.json '); Usernamespromise.then (fetchphotosofusers) . Then (applyinstagramfilters) and then (Uploadtrendyphotoalbum) . Then (Displaysuccessmessage, handleerrors);
- In the example above, if,
fetchPhotosOfUsers
applyInstagramFilters
or uploadTrendyPhotoAlbum方法中的任何一个返回一个reject promise,handleErrors将会携带着失败的原因被调用。
- In this way, promises approximates the asynchronous form of the Try-catch statement, preventing nested callbacks from nesting to the right, and promoting a more sensible way to manage complex asynchronous logic in your application.
5. The GUID does not intend to fully delve into the promises that can be used in all different ways, but if you want to learn more in depth, check RSVP, which is the promise library used by Ember.
Second, the router pauses for promises
1. When jumping between routers, the Ember router collects all the models (via model hooks) that are passed to the route controllers at the end of the jump.
If the model hook(or the associated Beforemodel, Aftermodel hooks) returns to the normal (Non-promise) object or array, the jump will be completed immediately.
But if the model hook(or the associated Beforemodel, Aftermodel hooks) returns a promise (or if a promise is provided as a Transitionto parameters), the jump will be paused, knowing the Promise Execution (Fullfill) or rejected (reject).
2. The router considers defining any object that has the then method as a promise.
3. If the promise executes (fullfill), the jump will go to where it left off and start parsing the model of the next route.
4. A basic example:
App/routes/tardy.js
export default Ember.Route.extend ({model () { return new Ember.RSVP.Promise (function (resolve) { Ember.run.later ( function () {Resolve ({ Msg: "hold Your Horses" }); }, 3000); }); }, Setupcontroller (Controller, model) {Console.log (model.msg); //
- When the jump enters route:tardy, themodel Hook is called and returns a promise, which will not be parsed resolve until 3 seconds after which the router pauses in the middle of the jump.
- When the promise is finally implemented, the router will continue to jump and eventually call Route:tardy 's setupcontroller Hook, with the parsed object.
5. This pause-on-promise is valuable when you need to ensure that the routed data is fully loaded before displaying a new template.
Third, when promises reject ...
We have covered the case of a model promise fulfillment, but if it refuses?
1. By default, if a model promise is rejected between jumps, the jump is terminated, no new target route template is rendered, and errors are logged to the console.
2. You can configure the error handler by using error handler in the routed actions hash . When a promise is rejected, an Error event will be activated on the route and bubbled to the default error handler of route:application unless it is handled through a custom error handler.
3. Example:
App/routes/good-for-nothing.js
export default Ember.Route.extend ({model { return Ember.RSVP.reject ("FAIL" // // Can transition to another the route here, e.g. // This.transitionto (' index '); // // return true;
- In the example above, the error event will stop in the route:good-for-nothing error handler and will not continue to bubble.
- In order for the event to continue bubbling to route:application, you can return truefrom the error handler.
Iv. Recovering from rejection
The rejected model promise terminates the jump, but because promises is coherent, you can capture the rejected promise itself in the model hook and convert them to implementations, which will not stop the jump.
App/routes/funky.js
default Ember.Route.extend ({ model () { return ihopethisworks (). Then (nullfunction () { // Promise rejected, fulfill with some default value to // c13>use as the route's model and continue on with the transition return {msg: "Recovered from Reje CTED promise " };});} );
V. Beforemodel and Aftermodel
1. For pause-on-promise jumps, the model hook contains several use cases, but sometimes you will need the help of the relevant Beforemodel and aftermodel hooks . The most common reason is if you jump to a route that contains a dynamic URL field by {{link-to}} or transitionto (instead of a change caused by a URL change) . The model of the route you are jumping on has been specified (for example, {{#link-to ‘article‘ article}}
or this.transitionTo(‘article‘, article)
), in which case the model hook will not be called.
In this case, you need to use Beformodel or aftermodel hooks to store the logic, while the router still collects all the routes models to perform the jump.
2. Beformodel
It is easy to be useful for both,Beforemodel hooks are called before the router attempts to parse the model for a given route. In other words, it is called before the model Hook is called, or if the model is not called, it is called before the router attempts to resolve any of the model promises that are passed to the route.
such as model, returning a promise from Beforemodel will pause the jump until it is parsed, or a eroorwill be activated if rejected.
3. Below is a list of far-from-exhaustive for a use case, where Beforemodel is very convenient:
- Decide whether to redirect to another route before executing a potentially wasteful query of the server in model .
- Ensure that the user has an authentication token before proceeding to the model.
- Application code that loads the secondary route requirements
- App/routes/secret-articles.js
default Ember.Route.extend ({ Beforemodel () { if (! this. Controllerfor (' auth '). Get (' isLoggedIn '){ this. Transitionto (' login '); } }});
4. Aftermodel
1. Aftermodel Hook is called after parsing a route's model (possibly a promise) and follows and Beforemodel the same pause-on-promise syntax as the model. It is passed to the model that has been parsed and therefore performs any additional logic that relies on the value of the fully parsed model.
2. Example
App/routes/articles.js
export default Ember.Route.extend ({model { // "this.store.findAll (' article ') ' Returns a Promise-like object // (it has a ' Then ' method so can be used like a promise ' this . Store.findall (' article ' ); }, Aftermodel (articles) { if (articles.get (' length ') = = = 1 this . Transitionto (' Article.show ', Articles.get (' Firstobject ') Span style= "color: #000000;" >)); } }});
3. You might ask why we can't just put aftermodel logic into the fulfill handler of the promise returned from the model: The reason is, as mentioned above, jump through {{link-to}} or Transitionto initialization, it is likely that the model has been provided for routing, so the model cannot be called in these cases.
4.10 Routing--Asynchronous Routing