How RSVP Handles Promises in Open Event Frontend

This blog post illustrates how to manage multiple promises simultaneously using a library known as RSVP in Open Event frontend.

What are Promises?

Promises are used to manage synchronous calls in javascript. Promises represent a value/object that may not be available yet but will become available in near future. To quote from MDN web docs:

The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.

What about RSVP?

Rsvp is a lightweight library used to organize asynchronous code. Rsvp provides several ways to handle promises and their responses. A very simple promise implementation using rsvp looks something like this.

var RSVP = require('rsvp');

var promise = new RSVP.Promise(function(resolve, reject) {
  // succeed
  resolve(value);
  // or reject
  reject(error);
});

promise.then(function(value) {
  // success
}).catch(function(error) {
  // failure
});

 

It’s simple, right? So, what it is doing is after it defines a promise it assumes two possible states of a promise which are resolve or reject and after promise has completed it executes the respective function.

Use in Open Event Frontend?

Almost all calls to open event server APIs are done asynchronously. One of the most significant use of rsvp comes when handling multiple promises in frontend and we want all of them to be evaluated at together. Unlike normal promises where each promises resolved or rejected individually, rsvp provides a promise.all() method which accepts array of promises and evaluates all at once. It then calls resolve or reject based on the status of all promises. A typical example where we use promise.all() is given here.

import Controller from '@ember/controller';
import RSVP from 'rsvp';
import EventWizardMixin from 'open-event-frontend/mixins/event-wizard';

export default Controller.extend(EventWizardMixin, {
 actions: {
   save() {
     this.set('isLoading', true);
     this.get('model.data.event').save()
       .then(data => {
         let promises = [];
         promises.push(this.get('model.data.event.tickets').toArray().map(ticket => ticket.save()));
         promises.push(this.get('model.data.event.socialLinks').toArray().map(link => link.save()));
         if (this.get('model.data.event.copyright.licence')) {
           let copyright = this.setRelationship(this.get('model.data.event.copyright.content'), data);
           promises.push(copyright.save());
         }
         if (this.get('model.data.event.tax.name')) {
           let tax = this.setRelationship(this.get('model.data.event.tax.content'), data);
           if (this.get('model.event.isTaxEnabled')) {
             promises.push(tax.save());
           } else {
             promises.push(tax.destroyRecord());
           }
         }
         RSVP.Promise.all(promises)
           .then(() => {
             this.set('isLoading', false);
             this.get('notify').success(this.get('l10n').t('Your event has been saved'));
             this.transitionToRoute('events.view.index', data.id);
           }, function() {
             this.get('notify').error(this.get('l10n').t('Oops something went wrong. Please try again'));
           });
       })
       .catch(() => {
         this.set('isLoading', false);
         this.get('notify').error(this.get('l10n').t('Oops something went wrong. Please try again'));
       });
   },
}

 

Here we made array of promises and then pushed each of the promises to it. Then at the end used this array of promises in RSVP.promise.all() which then evaluated it based on success or failure of the promises.

Resources: