ember-concurrency
ember-concurrency copied to clipboard
Consider putting the cancellation policy/lifetime, etc, on the callsite
Example app: https://ember-twiddle.com/4adde6ca35c70ee3ae57e8a10cf55176?openFiles=controllers.search.js%2C
-
Since tasks can be parameterized, it seems incorrect to tie the lifetime/cancellation policy to the task description. In the example, there are two consumers/callsites to the
searchtask, you want each of them to be restartable but allow both of them to run concurrently. (You can make a sub-task to work around it.) -
Tasks are not necessarily performed on the same object they are defined. For example, the
searchtask could have been defined on a service, and invoked in a component viathis.get('github.search').perform(...), in which case, e-c will not be able to tie this task to the component's lifetime correctly. -
We want a way to mark a task as dependent on its inputs and invalidate the result when they changes. @machty and I came up with the CP-pattern in the example which largely works, but again, you want each of the performs to be
restartable, not the whole task. -
Sometimes you want to perform a "fire-and-forget" task without linking its lifetime to the component.
Strawman:
import Ember from 'ember';
import { task } from 'ember-concurrency';
const { computed } = Ember;
function *reportUsage(ajax, searches) {
return ajax.post(`/analytics`, { searches });
}
export default Ember.Controller.extend({
...,
searches: 0,
search: function * (type, query) {
let result = yield this.get('ajax').request(`https://api.github.com/search/${type}?q=${query}`);
this.incrementProperty('searches');
return result.items;
},
userSearch: computed('query', function() {
let query = this.get('query');
return this.task('search') // <- sugar for `task(this.get('search').bind(this)).link(this) ?
.restartable('userSearch') // <- specify a unique id/scope, defaults to the identity of the function?
.perform('users', query);
}),
repoSearch: computed('query', function () {
let query = this.get('query');
return this.task('search')
.restartable('repoSearch')
.perform('repositories', query);
}),
willDestroy() {
let { ajax, searches } = this.getProperties('ajax', 'searches');
// Fire-and-forget: unlike `this.task`, the bare `task` function does not link by default,
// so this doesn't cancel itself when the component/controller dies
task(reportUsage).perform(ajax, searches);
this._super();
}
});