and

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 feature is experimental!

This API is still experimental, so it may change or be removed in future versions. You should not rely on it for production applications.

Signature

value(that)
forall e, v1, v2:
  (Task e v1).(Task e v2) => Task e (v1, v2)

Documentation

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.

Example:

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]);

Properties

Source Code

Defined in source/concurrency/task/_task.js at line 20, column 0
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;
        })
      });
    });
  }
Stability
experimental
Licence
MIT
Module
folktale/concurrency/task/_task
Authors
Copyright
(c) 2013-2017 Quildreen Motta, and CONTRIBUTORS
Authors
  • Quildreen Motta
Maintainers
  • Quildreen Motta <queen@robotlolita.me> (http://robotlolita.me/)