How to use asynchronous routing in Ember.js

Using Ember.js, it is possible to handle asynchronous logic. The ember router handles asynchronous logic with the concept of promises.

Promises

Promises represent eventual values in Ember. A promise can either be fulfilled or rejected. A fulfilled promise represents a value that has been resolved, while a rejected promise represents a value that has not been resolved.

We can retrieve a promise’s eventual value or handle a rejection case using a promise’s then() method.

The method takes two (optional) callbacks: one for fulfillment and the other for rejection. If the promise fulfills, the fulfillment method is called with the fulfilled value as its argument. If it is rejected, the rejection handler is called along with a reason for rejection.

Promises can also be chained together to perform sequential asynchronous operations.

Here’s an example that demonstrates the use of promises:

let promise = getEdpressoTagLine();

promise.then(fulfillCallback, rejectCallback);

function fulfillCallback(value) {
  console.log(`The tag line is ${value}`);
}

function rejectCallback(reason) {
  console.log(`Couldn't get the tag line! Reason: ${reason}`);
}

Using promises with fulfillment and rejection callbacks allows us to imitate an asynchronous form of the try-catch statements.

In the ember router, the different types of handling asynchronous logic (using promises) are as follows:

  1. The router pauses for promises

  2. When promises reject

  3. Recovering from rejection

The router pauses for promises

1. The router pauses for promises

When the ember router is transitioning between routes, we can complete the transition immediately by returning normal objects or arrays from the model. However, returning a promise from the model hook pauses the transition.

If the promise fulfills, the transition picks up where it left off.

The following example shows this process:

export default class PausedRoute extends Route {
  model() {
    return new Promise(function(resolve) {
      later(function() {
        resolve({ msg: 'How was the wait?' });
      }, 5000); // time in ms
    });
  }

  setupController(controller, model) {
    console.log(model.msg); // "How was the wait?"
  }
}

Running the above code on the ember server results in a five-second wait, after which the message "How was the wait?" is logged onto the screen.

This happens because the router pauses mid-transition until the promise is fulfilled. Since we purposefully added a 5000ms5 sec delay, we are able to observe the pause.

When promises reject

2. When promises reject

We have just learned that the router pauses the transition until the promise returned by the model is fulfilled. However, if a model promise rejects during a transition, the transition is aborted. No new destination route templates are rendered, and an error is logged to the console.

We can choose to handle the error event using a custom error handler, or allow the error to bubble up to the route:application's default error handler.

The following example shows this process:

export default class FailedRoute extends Route {
  model() {
    return Promise.reject("PROMISE REJECTED");
  }

  @action
  error(reason) {
    alert(reason); // "PROMISE REJECTED"

    // this.transitionTo('somewhere');

    // Uncomment the line below to bubble this error event:
    // return true;
  }
}

In the above example, the error event is handled and not allowed to bubble up to route:application's error handler.

However, returning true from the custom handler lets the error bubble up. Additionally, we can transition to another route using the transitionTo() method.

Recovering from rejection

3. Recovering from rejection

We can catch the promise rejects within the model hook and convert them into fulfills that do not put the transition on halt. This allows us to recover from rejection and does not abort the transition.

The following example shows this process:

export default class RecoveryRoute extends Route {
  model() {
    return ifRejected().catch(function() {
      // Promise rejected, fulfill with some default value
      return { msg: 'Recovered from rejected promise' };
    });
  }
}

In the above example, the promise is rejected. However, the rejected promise is caught within the model hook and converted into a fulfill.

Free Resources

Copyright ©2024 Educative, Inc. All rights reserved