This page is part of a static HTML representation of TriTarget.org at https://tritarget.org

PromiseProxyMixin

 8th January 2018 at 1:59pm

In Ember the PromiseProxyMixin is a pattern for wrapping a Promise in an object that reacts and provides some derived state about the promise.

It works very well with ObjectProxy or ArrayProxy.

Basic usage

const {
  Object: EmObject,
  PromiseProxyMixin
} = Ember;

const MyObject = EmObject.extend(PromiseProxyMixin);
let myObjectInstance = MyObject.create({
  promise: RSVP.resolve()
});

This will provide you with an object with the following properties:

  • isPending - Is the promise pending?
  • isSettled - Is the promise resolved or rejected?
  • isFulfilled - Is the promise resolved (fulfilled)?
  • isRejected - Is the promise rejected (error)?
  • content - The value if the promise has been fulfilled.
  • reason - The error if the promise has been rejected.

Due to Ember's aggressive stance on unhandled promises to use this in cases where you might expect the rejection to be handled in the template there is an extra step to prevent tests and the console from assuming it was an error: catch the PromiseProxyMixin not the original promise. This will resolve the promise so Ember can let it go but after the PromiseProxyMixin has already extracted its derived state and populated reason.

In Ember prior to version 2.11 you can not use PromiseProxyMixin with a component due to its asynchronous use of derived state it will cause a crash when a component is destroyed and the promise hasn't settled yet. Use an intermediate object instead.

Example Use

// app/components/my-component.js
import Ember from 'ember';

const {
  Component,
  Logger,
  ObjectProxy,
  PromiseProxyMixin,
  computed
} = Ember;

const Wrapper = ObjectProxy.extend(PromiseProxyMixin);

export default Component.extend({
  wrapper: computed('delayedValue', {
    get() {
      let promise = this.get('delayedValue');
      let wrapper = Wrapper.create({promise});
      // Stop an unhandled promise error because we handle the error in the
      // template.
      wrapper.catch(() => {});
      return wrapper;
    }
  })
});
{{! app/templates/components/my-component.hbs }}

{{#if wrapper.isPending}}
  Loading…
{{else if wrapper.isRejected}}
  Error: {{wrapper.reason}}
{{else}}
  {{! The actual object is in content but the properties are proxied and
  accessible directly without diving into content. }}
  Value: {{wrapper.content}}
{{/if}}