Previous: Route Tasks

Awaiting Multiple Child Tasks (or, cancelable Promise.all, Promise.race)

ember-concurrency provides Task-aware variants of Promise.all and Promise.race, which can be used in cases where a parent task wants to wait for multiple child tasks to run to completion (or throw an error) before continuing onward. The ember-concurrency variants both have the added benefit that if the parent task is canceled (or restarts), all of the child tasks will be automatically canceled. Similarly, in the case of all(), if any of the child tasks throws an error, all other child tasks are immediately canceled.

Live Example

The example below can be started (or restarted) using either all() to wait for all child tasks to run to completion, or race() to wait for the first. Note that how, in both cases, .maxConcurrency(3) ensures that only 3 progress tasks run at a time, but if you restart the task while it's running, it immediately starts 3 tasks after canceling the previous ones.

Status: Waiting...

import { task, timeout, all, race } from 'ember-concurrency';
const methods = { all, race };

const ProgressTracker = EmberObject.extend({
  id: null,
  percent: 0,
  word: null,
});

export default Controller.extend({
  status: "Waiting...",
  trackers: null,

  parent: task(function * (methodName) {
    let allOrRace = methods[methodName];
    let trackers = [], childTasks = [];

    for (let id = 0; id < 5; ++id) {
      let tracker = ProgressTracker.create({ id });
      trackers.push(tracker);
      childTasks.push(this.get('child').perform(tracker));
    }

    this.set('trackers', trackers);
    this.set('status', "Waiting for child tasks to complete...");
    let words = yield allOrRace(childTasks);
    this.set('status', `Done: ${makeArray(words).join(', ')}`);
  }).restartable(),

  child: task(function * (tracker) {
    let percent = 0;
    while (percent < 100) {
      yield timeout(Math.random() * 100 + 100);
      percent = Math.min(100, Math.floor(percent + Math.random() * 20));
      tracker.set('percent', percent);
    }
    let word = randomWord();
    tracker.set('word', word);
    return word;
  }).enqueue().maxConcurrency(3),

  colors: [ '#ff8888', '#88ff88', '#8888ff' ],
});
<p>
  <button onclick={{perform parent 'all'}}>all()</button>
  <button onclick={{perform parent 'race'}}>race()</button>
</p>




Previous: Route Tasks