Tasks Manage Cancellation, Race, Drop, and State
ember-concurrency — Better Than Promises
The ember-concurrency addon wraps async work with cancellation, drop and restartable semantics, and built-in isRunning flags.
What you'll learn
- Install the ember-concurrency package
- Define a task with the task helper
- Call perform and read the isRunning flag
ember-concurrency is the answer to “how do I cancel that fetch?” and “how
do I show a spinner?” in idiomatic Ember. It wraps async work in tasks
that you perform, with built-in state and cancellation.
Install
ember install ember-concurrency Define A Task
import Component from '@glimmer/component';
import { task } from 'ember-concurrency';
import { service } from '@ember/service';
export default class Search extends Component {
@service store;
searchTask = task(async (query) => {
return this.store.query('post', { q: query });
});
} Perform From The Template
<input {{on "input" (perform this.searchTask)}} />
{{#if this.searchTask.isRunning}}
<Spinner />
{{else if this.searchTask.last.value}}
<ul>
{{#each this.searchTask.last.value as |post|}}
<li>{{post.title}}</li>
{{/each}}
</ul>
{{/if}} What A Task Gives You
Every task instance has:
isRunning— true while at least one perform is in flightisIdle— opposite of isRunninglast— the most recent task instance (with.value,.error, etc.)lastSuccessful,lastErrored,lastCanceledperformCount— how many times it has been called
These are all @tracked, so templates re-render when they change.
Cancellation
Calling task.cancelAll() cancels in-flight runs. Cancellation propagates
through generator/async — pending awaits throw a cancellation error that
ember-concurrency swallows.