Skip to content
Effect 4.0 is here. One ecosystem. Zero dependencies.

Deferred

One-time coordination cells for Effect programs. A Deferred<A, E> starts empty, can be completed exactly once with a success, failure, defect, or interruption, and lets any number of fibers wait for that result. Awaiting a Deferred suspends the fiber instead of blocking an operating-system thread, and every waiter observes the same completion.

24 exports Since v2.0.0 Source

Completion

Since v2.0.0

Runs the supplied Effect and attempts to complete the Deferred with its memoized result.

When to use

Use when completing a Deferred should run an effect once and share its result with all awaiters.

Details

The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

See

  • completeWith for storing an effect directly without memoizing its result

Signature

declare const complete: {
<A, E, R>(effect: Effect<A, E, R>): (self: Deferred<A, E>) => Effect<boolean, never, R>;
<A, E, R>(self: Deferred<A, E>, effect: Effect<A, E, R>): Effect<boolean, never, R>;
}

Example Completing a Deferred from an effect

import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const completed = yield* Deferred.complete(deferred, Effect.succeed(42))
const value = yield* Deferred.await(deferred)
return [completed, value]
})
await Effect.runPromise(program) // => [true, 42]

Attempts to complete the Deferred with the specified effect directly.

When to use

Use to store an already environment-free effect as the completion without running it during completion.

Details

The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

Gotchas

The supplied effect is not memoized by completeWith; each awaiter may run the stored effect independently.

See

  • complete for running an effect once and sharing its result
  • done for completing from an already computed Exit

Signature

declare const completeWith: {
<A, E>(effect: Effect<A, E>): (self: Deferred<A, E>) => Effect<boolean>;
<A, E>(self: Deferred<A, E>, effect: Effect<A, E>): Effect<boolean>;
}

Example Completing a Deferred with an effect

import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const completed = yield* Deferred.completeWith(deferred, Effect.succeed(42))
const value = yield* Deferred.await(deferred)
return [completed, value]
})
await Effect.runPromise(program) // => [true, 42]
Since v2.0.0

Attempts to complete the Deferred with a defect.

When to use

Use to complete a Deferred with an unexpected defect.

Details

Fibers waiting on the Deferred die with that defect only if this call completes it. The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

Signature

declare const die: {
(defect: unknown): <A, E>(self: Deferred<A, E>) => Effect<boolean>;
<A, E>(self: Deferred<A, E>, defect: unknown): Effect<boolean>;
}

Example Killing a Deferred with a defect

import { Deferred, Effect, Exit } from "effect"
const defect = new Error("Something went wrong")
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const success = yield* Deferred.die(deferred, defect)
const exit = yield* Effect.exit(Deferred.await(deferred))
return [success, exit]
})
await Effect.runPromise(program) // => [true, Exit.die(defect)]
Since v2.0.0

Computes a defect when the returned effect is run, then attempts to complete the Deferred with that defect.

When to use

Use to lazily compute an unexpected defect when the completion effect runs.

Details

Fibers waiting on the Deferred die with the computed defect only if this call completes it. The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

Signature

declare const dieSync: {
(evaluate: LazyArg<unknown>): <A, E>(self: Deferred<A, E>) => Effect<boolean>;
<A, E>(self: Deferred<A, E>, evaluate: LazyArg<unknown>): Effect<boolean>;
}

Example Killing a Deferred with a lazy defect

import { Deferred, Effect, Exit } from "effect"
const defect = new Error("Lazy error")
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const success = yield* Deferred.dieSync(deferred, () => defect)
const exit = yield* Effect.exit(Deferred.await(deferred))
return [success, exit]
})
await Effect.runPromise(program) // => [true, Exit.die(defect)]
Since v2.0.0

Completes the Deferred with the specified Exit value, which will be propagated to all fibers waiting on the value of the Deferred.

When to use

Use to complete a Deferred from an already computed Exit.

Details

The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

See

  • complete for completing from an effect and memoizing its result
  • completeWith for storing an effect directly
  • succeed for completing with a success value
  • failCause for completing with a failure cause

Signature

declare const done: {
<A, E>(exit: Exit<A, E>): (self: Deferred<A, E>) => Effect<boolean>;
<A, E>(self: Deferred<A, E>, exit: Exit<A, E>): Effect<boolean>;
}

Example Completing a Deferred with an Exit

import { Deferred, Effect, Exit } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
yield* Deferred.done(deferred, Exit.succeed(42))
return yield* Effect.exit(Deferred.await(deferred))
})
await Effect.runPromise(program) // => Exit.succeed(42)
Since v2.0.0

Attempts to complete the Deferred with the specified error.

When to use

Use to complete a Deferred with a typed failure value.

Details

Fibers waiting on the Deferred fail with that error only if this call completes it. The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

Signature

declare const fail: {
<E>(error: E): <A>(self: Deferred<A, E>) => Effect<boolean>;
<A, E>(self: Deferred<A, E>, error: E): Effect<boolean>;
}

Example Failing a Deferred with an error

import { Deferred, Effect, Exit } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number, string>()
const success = yield* Deferred.fail(deferred, "Operation failed")
const exit = yield* Effect.exit(Deferred.await(deferred))
return [success, exit]
})
await Effect.runPromise(program) // => [true, Exit.fail("Operation failed")]

Attempts to complete the Deferred with the specified Cause.

When to use

Use to complete a Deferred with a full failure cause.

Details

Fibers waiting on the Deferred observe that cause only if this call completes it. The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

Signature

declare const failCause: {
<E>(cause: Cause<E>): <A>(self: Deferred<A, E>) => Effect<boolean>;
<A, E>(self: Deferred<A, E>, cause: Cause<E>): Effect<boolean>;
}

Example Failing a Deferred with a Cause

import { Cause, Deferred, Effect, Exit } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number, string>()
const success = yield* Deferred.failCause(deferred, Cause.fail("Operation failed"))
const exit = yield* Effect.exit(Deferred.await(deferred))
return [success, exit]
})
await Effect.runPromise(program) // => [true, Exit.failCause(Cause.fail("Operation failed"))]

Computes a Cause when the returned effect is run, then attempts to complete the Deferred with that cause.

When to use

Use to lazily compute a full failure cause when the Deferred completion effect runs.

Details

Fibers waiting on the Deferred observe the computed cause only if this call completes it. The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

Signature

declare const failCauseSync: {
<E>(evaluate: LazyArg<Cause<E>>): <A>(self: Deferred<A, E>) => Effect<boolean>;
<A, E>(self: Deferred<A, E>, evaluate: LazyArg<Cause<E>>): Effect<boolean>;
}

Example Failing a Deferred with a lazy Cause

import { Cause, Deferred, Effect, Exit } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number, string>()
const success = yield* Deferred.failCauseSync(deferred, () => Cause.fail("Lazy error"))
const exit = yield* Effect.exit(Deferred.await(deferred))
return [success, exit]
})
await Effect.runPromise(program) // => [true, Exit.failCause(Cause.fail("Lazy error"))]
Since v2.0.0

Computes an error when the returned effect is run, then attempts to complete the Deferred with that error.

When to use

Use to lazily compute a typed failure value when the Deferred completion effect runs.

Details

Fibers waiting on the Deferred fail with the computed error only if this call completes it. The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

Signature

declare const failSync: {
<E>(evaluate: LazyArg<E>): <A>(self: Deferred<A, E>) => Effect<boolean>;
<A, E>(self: Deferred<A, E>, evaluate: LazyArg<E>): Effect<boolean>;
}

Example Failing a Deferred with a lazy error

import { Deferred, Effect, Exit } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number, string>()
const success = yield* Deferred.failSync(deferred, () => "Lazy error")
const exit = yield* Effect.exit(Deferred.await(deferred))
return [success, exit]
})
await Effect.runPromise(program) // => [true, Exit.fail("Lazy error")]

Attempts to complete the Deferred with interruption by the current fiber.

When to use

Use to complete a Deferred as interrupted by the current fiber.

Details

Fibers waiting on the Deferred are interrupted with the current fiber id only if this call completes it. The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

Signature

declare function interrupt<A, E>(self: Deferred<A, E>): Effect<boolean>

Example Interrupting a Deferred

import { Deferred, Effect, Exit } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const success = yield* Deferred.interrupt(deferred)
const exit = yield* Effect.exit(Deferred.await(deferred))
return [success, exit] as const
})
const [success, exit] = await Effect.runPromise(program)
success // => true
Exit.hasInterrupts(exit) // => true

Attempts to complete the Deferred with interruption by the specified FiberId.

When to use

Use to complete a Deferred as interrupted by a specific fiber id.

Details

Fibers waiting on the Deferred are interrupted with that fiber id only if this call completes it. The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

Signature

declare const interruptWith: {
(fiberId: number): <A, E>(self: Deferred<A, E>) => Effect<boolean>;
<A, E>(self: Deferred<A, E>, fiberId: number): Effect<boolean>;
}

Example Interrupting a Deferred with a fiber id

import { Deferred, Effect, Exit } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const success = yield* Deferred.interruptWith(deferred, 42)
const exit = yield* Effect.exit(Deferred.await(deferred))
return [success, exit]
})
await Effect.runPromise(program) // => [true, Exit.interrupt(42)]
Since v4.0.0

Runs an Effect and attempts to complete a Deferred with the effect's result.

When to use

Use to pipe an effect result into a Deferred while preserving success, failure, defects, and interruption.

Details

If the effect succeeds, fails, dies, or is interrupted, that result is used as the attempted completion. The returned effect cannot fail; it succeeds with true if it completed the Deferred, or false if the Deferred was already completed.

Signature

declare const into: {
<A, E>(deferred: Deferred<A, E>): <R>(self: Effect<A, E, R>) => Effect<boolean, never, R>;
<A, E, R>(self: Effect<A, E, R>, deferred: Deferred<A, E>): Effect<boolean, never, R>;
}

Example Completing a Deferred from an effect result

import { Deferred, Effect } from "effect"
const successEffect = Effect.succeed(42)
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number, string>()
const isCompleted = yield* Deferred.into(successEffect, deferred)
const value = yield* Deferred.await(deferred)
return [isCompleted, value]
})
await Effect.runPromise(program) // => [true, 42]
Since v2.0.0

Attempts to complete the Deferred with the specified value.

When to use

Use to complete a Deferred with a successful value.

Details

Fibers waiting on the Deferred receive the value only if this call completes it. The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

Signature

declare const succeed: {
<A>(value: A): <E>(self: Deferred<A, E>) => Effect<boolean>;
<A, E>(self: Deferred<A, E>, value: A): Effect<boolean>;
}

Example Completing a Deferred with a value

import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
yield* Deferred.succeed(deferred, 42)
return yield* Deferred.await(deferred)
})
await Effect.runPromise(program) // => 42
Since v2.0.0

Computes a value when the returned effect is run, then attempts to complete the Deferred with that value.

When to use

Use to lazily compute a successful value when the Deferred completion effect runs.

Details

Fibers waiting on the Deferred receive the computed value only if this call completes it. The returned effect succeeds with true when this call completed the Deferred, or false if it was already completed.

Signature

declare const sync: {
<A>(evaluate: LazyArg<A>): <E>(self: Deferred<A, E>) => Effect<boolean>;
<A, E>(self: Deferred<A, E>, evaluate: LazyArg<A>): Effect<boolean>;
}

Example Completing a Deferred with a lazy value

import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
yield* Deferred.sync(deferred, () => 42)
return yield* Deferred.await(deferred)
})
await Effect.runPromise(program) // => 42

Constructors

Since v2.0.0

Creates a new Deferred.

When to use

Use to allocate an empty Deferred inside an Effect workflow.

Signature

declare function make<A, E = never>(): Effect<Deferred<A, E>>

Example Creating a Deferred

import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
yield* Deferred.succeed(deferred, 42)
return yield* Deferred.await(deferred)
})
await Effect.runPromise(program) // => 42

Getters

Since v2.0.0

Returns the current completion effect as an Option. This returns Option.some(effect) when the Deferred is completed, Option.none() otherwise.

When to use

Use to inspect whether a Deferred is already completed and retrieve its stored completion effect when available.

Signature

declare function poll<A, E>(self: Deferred<A, E>): Effect<Option<Effect<A, E, never>>>

Example Polling Deferred completion

import { Deferred, Effect, Option } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const beforeCompletion = yield* Deferred.poll(deferred)
yield* Deferred.succeed(deferred, 42)
const afterCompletion = yield* Deferred.poll(deferred)
const afterValue = yield* Effect.transposeOption(afterCompletion)
return [beforeCompletion, afterValue]
})
await Effect.runPromise(program) // => [Option.none(), Option.some(42)]

Guards

Checks whether a value is a Deferred.

When to use

Use to validate unknown values at runtime boundaries before treating them as Deferred values.

Signature

declare function isDeferred<A, E>(u: unknown): u is Deferred<A, E>

Models

Deferred

interface
Since v2.0.0

A Deferred represents an asynchronous variable that can be set exactly once, with the ability for an arbitrary number of fibers to suspend (by calling Deferred.await) and automatically resume when the variable is set.

When to use

Use to coordinate multiple fibers around a value or failure that will be supplied exactly once.

Signature

interface Deferred<in out A, in out E = never> extends Variance<A, E>, Pipeable {
effect?: Effect<A, E, never>;
resumes?: Array<(effect: Effect<A, E>) => void>;
}

Example Creating a Deferred for inter-fiber communication

import { Deferred, Effect, Fiber } from "effect"
const program = Effect.gen(function*() {
const deferred: Deferred.Deferred<string> = yield* Deferred.make<string>()
const producer = yield* Effect.forkChild(
Effect.gen(function*() {
yield* Deferred.succeed(deferred, "Hello, World!")
})
)
const consumer = yield* Effect.forkChild(Deferred.await(deferred))
yield* Fiber.join(producer)
return yield* Fiber.join(consumer)
})
await Effect.runPromise(program) // => "Hello, World!"

Other

Signature

declare function await<A, E>(self: Deferred<A, E>): Effect<A, E>
Since v2.0.0

Companion namespace containing type-level metadata for Deferred.

When to use

Use to reference type-level metadata associated with Deferred.

Predicates

Since v2.0.0

Returns true if this Deferred has already been completed with a value or an error, false otherwise.

When to use

Use to check completion status inside an Effect workflow.

Signature

declare function isDone<A, E>(self: Deferred<A, E>): Effect<boolean>

Example Checking Deferred completion

import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const beforeCompletion = yield* Deferred.isDone(deferred)
yield* Deferred.succeed(deferred, 42)
const afterCompletion = yield* Deferred.isDone(deferred)
return [beforeCompletion, afterCompletion]
})
await Effect.runPromise(program) // => [false, true]

Returns whether this Deferred has already been completed synchronously.

When to use

Use to check Deferred completion synchronously in code that cannot return an Effect, such as low-level integration code.

See

  • isDone for checking completion inside Effect
  • poll for reading the completed effect when available

Signature

declare function isDoneUnsafe<A, E>(self: Deferred<A, E>): boolean

Unsafe

Attempts to complete the Deferred synchronously with the specified completion effect.

When to use

Use to complete a Deferred synchronously in low-level code that already has the completion effect.

Details

This mutates the Deferred directly and should be reserved for low-level code; prefer the effectful completion APIs when possible. Returns true if this call completed the Deferred, or false if it was already completed.

Signature

declare function doneUnsafe<A, E>(self: Deferred<A, E>, effect: Effect<A, E>): boolean

Example Completing a Deferred unsafely

import { Deferred, Effect } from "effect"
const deferred = Deferred.makeUnsafe<number>()
Deferred.doneUnsafe(deferred, Effect.succeed(42)) // => true

Creates an empty Deferred synchronously outside the Effect runtime.

When to use

Use to allocate a Deferred synchronously when direct allocation outside Effect is required.

Signature

declare function makeUnsafe<A, E = never>(): Deferred<A, E>

Example Creating a Deferred unsafely

import { Deferred } from "effect"
const deferred = Deferred.makeUnsafe<number>()
Deferred.isDoneUnsafe(deferred) // => false