Let's say, for example that I call `doTasks()` with 10 separate tasks. Before any of them can complete, one of them fails. What happens to the other 9? In your example, they are "leaked" because they will continue running, even though the scope that was awaiting their results in gone. Using a "worker pool" as in the example, it might go something like this:
async function doTasks(tasks = []) {
let workerpool = new WorkerPool();
try {
for (let task of tasks) {
workerpool.exec("my task", task);
}
let results = await workerpool.all();
// do stuff with results
} finally {
// no matter the outcome, nothing outlives this scope.
await workerpool.destroy();
}
}
It should be noted that cancellation, i.e. the ability to "destroy" a concurrent task is a necessary primitive for structured concurrency. You can think of it as the equivalent of automatically releasing memory at the end of a lexical scope.There is already an implementation of Structured Concurrency for JavasScript here https://frontside.com/effection