A Monad that can describe asynchronous or synchronous computations that produce exactly one result.

import cats.effect.{LiftIO, Sync}

trait Async[F[_]] extends Sync[F] with LiftIO[F] {
  def async[A](k: (Either[Throwable, A] => Unit) => Unit): F[A]

This type class allows the modeling of data types that:

  • Can start asynchronous processes.
  • Can emit one result on completion.
  • Can end in error

Important: on the “one result” signaling, this is not an “exactly once” requirement. At this point streaming types can implement Async and such an “exactly once” requirement is only clear in Effect.

Therefore the signature exposed by the Async.async builder is this:

(Either[Throwable, A] => Unit) => Unit

Important: such asynchronous processes are not cancelable. See the Concurrent alternative for that.

On Asynchrony

An asynchronous task represents logic that executes independent of the main program flow, or current callstack. It can be a task whose result gets computed on another thread, or on some other machine on the network.

In terms of types, normally asynchronous processes are represented as:

(A => Unit) => Unit

This signature can be recognized in the “Observer pattern” described in the “Gang of Four”, although it should be noted that without an onComplete event (like in the Rx Observable pattern) you can’t detect completion in case this callback can be called zero or multiple times.

Some abstractions allow for signaling an error condition (e.g. MonadError data types), so this would be a signature that’s closer to Scala’s Future.onComplete:

(Either[Throwable, A] => Unit) => Unit

And many times the abstractions built to deal with asynchronous tasks also provide a way to cancel such processes, to be used in race conditions in order to cleanup resources early:

(A => Unit) => Cancelable

This is approximately the signature of JavaScript’s setTimeout, which will return a “task ID” that can be used to cancel it. Important: this type class in particular is NOT describing cancelable async processes, see the Concurrent type class for that.


The async method has an interesting signature that is nothing more than the representation of a callback-based API function. For example, consider the following example having an API that returns a Future[String] as a response:

import cats.effect.{IO, Async}

import scala.concurrent.Future

val apiCall = Future.successful("I come from the Future!")

val ioa: IO[String] =
  Async[IO].async { cb =>
    import scala.util.{Failure, Success}

    apiCall.onComplete {
      case Success(value) => cb(Right(value))
      case Failure(error) => cb(Left(error))


In the example above ioa will have a successful value A or it will be raise an error in the IO context.