Previous: Testing & Debugging
Next: FAQ & Fact Sheet
Ember Concurrency tasks play nicely with TypeScript and all of the APIs covered in these docs. Here is an example of a TypeScript component with an ember-concurrency task:
import Component from '@glimmer/component';
import { task, timeout } from 'ember-concurrency';
export default class extends Component {
myTask = task(async (ms: number) => {
await timeout(ms);
return 'done!';
});
}
Ember Concurrency provides a template registry for using the
perform
,
cancel-all
, and
task
helpers within handlebars templates in Glint "loose mode". See the example
below for how to include Ember Concurrency's template registry in your Glint
configuration.
// e.g. types/glint.d.ts
import '@glint/environment-ember-loose';
import type EmberConcurrencyRegistry from 'ember-concurrency/template-registry';
declare module '@glint/environment-ember-loose/registry' {
export default interface Registry
extends EmberConcurrencyRegistry /* other addon registries */ {
// local entries
}
}
Here is an example of a modern .gts file in "strict mode" which imports the
classic
perform
helper from Ember Concurrency.
Note: while you can import and use the
perform
helper, it is actually recommended to use the
.perform()
method on each task, which is internally bound to the task (similar to methods
decorated with
@action
). One of the benefits of using the
.perform()
method is that it can be used with modern idiomatic patterns like using the
fn
helper to curry additional args when performing the task.
Pardon the lack of syntax! PR's welcome to improve our syntax highlighting!
import Component from "@glimmer/component";
import { task } from "ember-concurrency";
import perform from "ember-concurrency/helpers/perform";
import { on } from "@ember/modifier";
import { fn } from "@ember/helper";
export default class Demo extends Component {
taskNoArgs = task(async () => {
console.log("Look ma, no args!");
});
taskWithArgs = task(async (value: string) => {
console.log(value);
});
<template>
<button type="button" {{on "click" this.taskNoArgs.perform}}>
Task with no Params (.perform method) (RECOMMENDED)
</button>
<button type="button" {{on "click" (perform this.taskNoArgs)}}>
Task with no Params (with classic perform helper)
</button>
<button type="button" {{on "click" (fn this.taskNoArgs.perform '123')}}>
Task with Params (currying with fn helper) (RECOMMENDED)
</button>
<button type="button" {{on "click" (perform this.taskWithArgs '123')}}>
Task with Params (currying with classic perform helper)
</button>
</template>
}
Task
objectsIn most cases, you don't need to provide type annotations for your task, but when you do (such as when specifying the Args of a Glimmer component), you can use the Task type:
import Component from '@glimmer/component';
import { task, timeout } from 'ember-concurrency';
import type { Task } from 'ember-concurrency';
// Define a Type task that takes a single number argument and returns a string
type MyTaskType = Task<string, [number]>;
interface Args {
fooTask: MyTaskType;
}
export default class extends Component<Args> {
slowlyComputeStringLength: MyTaskType = task(async (ms: number) => {
await timeout(ms);
const length = await this.args.fooTask.perform(ms);
return length;
});
}
Previous: Testing & Debugging
Next: FAQ & Fact Sheet