nypublicradio/ember-hifi

View on GitHub
addon/utils/promise-race.js

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
import { copy } from 'ember-copy';
import RSVP from 'rsvp';
/**
 * Given an array of params, this will go through the list one-by-one and call your
 * callback function until your function calls returnSuccess, at which point the
 * main Promise will resolve with that thing you passed it.
 *
 * The callback should have the following arguments (nextParam, returnSuccess, markAsFailure)

 * Your callback should do what it needs to do and if that thing is good, pass it to
 * returnSuccess. If that thing is bad call markAsFailure
 *
 * @class PromiseRace
 * @method start
 * @param {Array} params
 * @param {Function} callback(nextParam, returnSuccess, markAsFailure)
 * @return {Promise  {result, failures} }
 */

function start(params, callback) {
  return new RSVP.Promise((resolve, reject) => {
    let paramsToTry = copy(params);
    var failures = [];

    (function tryNext(tryThis) {
      tryThis
        .then(success => {
          resolve({ success, failures });
        })
        .catch(failure => {
          if (failure) {
            failures.push(failure);
          }
          let nextParam = paramsToTry.shift();
          if (!nextParam) {
            let error = new Error('All given promises failed.');
            error.failures = failures;
            reject(error);
          }
          else {
            return tryNext(promisifyCallback(callback, nextParam));
          }
      });
    })(promisifyCallback(callback, paramsToTry.shift()));
  });
}

function promisifyCallback(callback, nextParam) {
  return new RSVP.Promise((returnSuccess, markFailure) => {
    callback(nextParam, returnSuccess, markFailure);
  });
}

export default {
  start: start
};