Constructs a new task that awaits both tasks to resolve. The result of the new task is a tuple containing the results of the left and right tasks, if they all succeed, or the first failure if they fail.
This API is still experimental, so it may change or be removed in future versions. You should not rely on it for production applications.
Constructs a new task that awaits both tasks to resolve. The result of the new task is a tuple containing the results of the left and right tasks, if they all succeed, or the first failure if they fail.
While the tasks are started from left-to-right, the method will not wait one task to finish before starting another. For asynchronous tasks this effectively gives you concurrent execution.
Note that cancelling one of the input tasks will cancel the combined tasks as well. Cancelling the combined tasks will cancell both input tasks. If any of the input tasks fail, the other input task will be cancelled as well.
If you need to combine more than two tasks concurrently, take a look at the waitAll
function in the concurrency/task
module.
const { task } = require('folktale/concurrency/task');
const delay = (ms) => task(
resolver => {
const timerId = setTimeout(() => resolver.resolve(ms), ms);
resolver.cleanup(() => {
clearTimeout(timerId);
});
}
);
const result = await delay(30).and(delay(40)).run().promise();
$ASSERT(result == [30, 40]);
and(that) {
return new Task(resolver => { // eslint-disable-line max-statements
let thisExecution = this.run(); // eslint-disable-line prefer-const
let thatExecution = that.run(); // eslint-disable-line prefer-const
let valueLeft = null;
let valueRight = null;
let doneLeft = false;
let doneRight = false;
let cancelled = false;
resolver.onCancelled(() => {
thisExecution.cancel();
thatExecution.cancel();
});
const guardResolve = (setter) => (value) => {
if (cancelled) return;
setter(value);
if (doneLeft && doneRight) {
resolver.resolve([valueLeft, valueRight]);
}
};
const guardRejection = (fn, execution) => (value) => {
if (cancelled) return;
cancelled = true;
execution.cancel();
fn(value);
};
thisExecution.listen({
onRejected: guardRejection(resolver.reject, thatExecution),
onCancelled: guardRejection(resolver.cancel, thatExecution),
onResolved: guardResolve(x => {
valueLeft = x;
doneLeft = true;
})
});
thatExecution.listen({
onRejected: guardRejection(resolver.reject, thisExecution),
onCancelled: guardRejection(resolver.cancel, thisExecution),
onResolved: guardResolve(x => {
valueRight = x;
doneRight = true;
})
});
});
}