-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Encapsulated tasks #7
Comments
I am loving the project as I am missing ember-concurrency a lot. Thanks for the effort! How would you substitute encapsulated tasks with composition API? Thx for the feedback and all the good work! |
Hey thanks for this question, I was wondering about it as well! One easy step towards this would be just bind some object to the task callback. It would allow you to persist some state between performs without reaching outside of the task. const task = useTask(function * () {
this.foo = 'bar';
}); Since But that's not all what encapsulated tasks do. To also allow initial state and computed values, it would have to prob. look something like this: const task = useStatefulTask({
progress: 0
progressPct: computed() => `${task.state.progress * 100}%`,
*perform() {
while (this.progress < 100) {
yield timeout(500);
this.progress = this.progress + 0.01;
}
return 'done';
}
}); The difference here would be probably that the state would be nested under Possible implementation could look like this: export function useStatefulTask(taskContent) {
const cb = taskContent.perform;
const _contentWithoutPerform = { ...taskContent };
delete _contentWithoutPerform.perform;
const state = reactive(_contentWithoutPerform);
return useTask(cb.bind(state)).withState(state);
} But then again - is this really needed with composition API? In Ember, changing I guess with Composition API the way to encapsulate is to... compose. export function useProgress() {
const progress = ref(0);
const task = useTask(function *() { /* ... */);
return { progress, task };
} But still, I feel like there could be some benefits to |
Hey Martin Thanks for the fast and long feedback. Encapsulated tasks encapsulate a task instance not a task. Let me give you an example for the benefits of encapsulated task: Think of a task that handles file uploads for you. You pass the task a file and it uploads it to the server. How about the remaining file size? You could do it the old-fashioned way and create a component state or task state called Encapsulated tasks give you additional task instance state and computed properties. Each instance can have its own I hope this makes sense! |
Ahh, thanks a lot for these clarifications! I totally misunderstood that the state is encapsulated per instance, not per task as a whole.
This is really a great example and ideal usecase for the encapsulated tasks. Let me think how I'd go around solving this with Composition API. Probably the task would have to wrapped in some bigger, custom, data structure.
Instead of doing const files = ref([]);
const addFile = (file) => {
const progress = ref(0);
const taskInstance = uploadTask.perform(progress);
const fileState = reactive({
file,
progress,
result: taskInstance, // used to check for error and cancelation in the template
progressPct: computed() => `${fileState.progress * 100}%`,
remainingSize: computed() => {}, // some computation using `file` and `progress` here?
});
files.push(fileState);
} In this case, the task would accept a ref and change it as needed during the run. I can see there is some overhead here that the encapsulated tasks could solve though.
I guess there could be both So if I modify the examples above: const task = useStatefulTask({
progress: 0
progressPct: computed() => `${task.state.progress * 100}%`, // hm - no way to refer to the current instance here :(
*perform() {
while (this.progress < 100) {
yield timeout(500);
this.progress = this.progress + 0.01;
}
return 'done';
}
}); This would kinda work. In order to show all the files in the template you could iterate over all running instances and show No need to create extra
Having some kind of setup function in the task is an interesting idea as well and would for sure allow bigger flexibility. In this case the It seems there is a potential for I'll look for potential usecase for encapsulated tasks in my work projects. When I find one, I'll try to experiment some more (create actual working prototype:)). |
Cool! I am in favor for the idea of
I get confused by task and taskInstance too. I was wondering, if taskInstance is the wrong name? The Task Instance is in OOP the Instance of the task. Therefore, the object where you can call |
I'd say the returned value should still end up on So I still didn't have a usecase for this though. I can imagine some kind of multi-file upload would indeed be ideal (each while being one task instance).
Yeah it is a bit unfortunate. Especially here. In ember-concurrency it makes more sense because Ember itself is more OOP and ember-concurrency is also more object-oriented under the hood. But even there TaskInstance is not a true instance of a Task in the OOP sense. Still I decided to keep the naming so that vue-concurrency si as close to ember-concurrency as possible. There's benefits to this consistency I think. But perhpaps there could be an upcoming major release that would introduce more fitting naming. |
Soo, I happened to implement some upload with progress indicator and I can totally see a usecase for something like I hacked a solution using normal tasks + refs on the side, but I'll try to refactor later with some new abstraction. Hopefully soon 🙏 |
Haha, you are right. But for everything that is powerful you must restrain yourself when to use it. The Composition API has the same pitfalls ;) |
it seems like there's less need for this with Composition API than on the Ember side, but it still might be useful.
http://ember-concurrency.com/docs/encapsulated-task
The text was updated successfully, but these errors were encountered: