Exposes underlying errors by lifting both successful and failed
results into an Either value.
Given that errors are short-circuiting the processing of flatMap
chains, this method is useful for exposing errors such that you can
flatMap over them.
const f: Future<number> = Future.raise(new DummyError)
// Yields a successful Left(DummyError) on completion
const fe: Future<Either<Throwable, number>> = f.attempt()
// Yields a Right(1) on completion
const fr: Future<Either<Throwable, number>> = Future.pure(1).attempt()
Delays signaling the result of this Future by the specified duration.
It works for successful results:
const fa = Future.of(() => "Alex")
// Delays the signaling by 1 second
fa.delayResult(1000).flatMap
And for failures as well:
Future.raise(new TimeoutError()).delayResult(1000)
is the duration to wait before signaling the final result
Chains asynchronous operations.
Creates a new future by applying a function to the successful result of the source and returns the result of the function as the new future. If this future is completed with an exception then the new future will also contain this exception.
This operation is the monadic bind (e.g. Monad.flatMap).
const fa = Future.of(() => 3)
const fb = Future.of(() => 5)
// Yields 3 + 5
fa.flatMap(a => fb.map(b => a + b))
Asynchronously processes the value in the future once the value becomes available.
WARNING: Will not be called if this future is never completed or if it is completed with a failure.
the function which will be executed if this Future completes with a result
Given a mapping function, transforms the successful result of the source.
If the source is completed with an exception, then the new future will also be completed in an error.
This operation is the functor map (e.g. Functor.map).
const f = Future.of(() => "The future")
const g = f.map(x => x + " is now!")
Creates a new future that will handle any matching throwable that this future might contain by assigning it a value.
This operation is the equivalent of map for handling errors. Also see transform, which can handle both successful results and failures.
const f = Future.of<number>(() => { throw new DummyError() })
f.recover(e => {
if (e instanceof DummyError) return 10
// Don't re-throw exceptions like this, use `recoverWith` instead!
throw e
})
Creates a new future that will handle any matching throwable that this future might contain by assigning it a value of another future.
This operation is the equivalent of flatMap for handling errors. Also see transformWith, which can handle both successful results and failures.
const f = Future.of<number>(() => { throw new DummyError() })
f.recoverWith(e => e instanceof DummyError
? Future.pure(10) // Fallback
: Future.raise(e) // Re-throw
)
JavaScript Thenable implementation, needed in order to await Future
values in async functions.
Returns a future that mirrors the source in case the result of the source
is signaled within the required after duration, otherwise it
fails with a TimeoutError, cancelling the source.
const fa = Future.of(() => 1).delayResult(10000)
// Will fail with a TimeoutError
fa.timeout(1000)
is the duration to wait until it triggers the timeout error
Returns a future that mirrors the source in case the result of the source
is signaled within the required after duration, otherwise it
triggers the execution of the given fallback after the duration has
passed, cancelling the source.
This is literally the implementation of Future.timeout:
const fa = Future.of(() => 1).delayResult(10000)
fa.timeoutTo(1000, () => Future.raise(new TimeoutError()))
is the duration to wait until it triggers the fallback
is a thunk generating a fallback Future to timeout to
Transforms the sources, regardless if the result is a failure or a success.
This function is a combination of map and recover, being the (type safe) alternative to JavaScript's then from the Promises/A+ specification.
Example:
import { Left, Right } from "funfix"
// Expose errors by lifting them to an Either<Error, A>
future.transform<Either<Throwable, A>>(Left, Right)
Also see transformWith.
is the function that's going to get executed in case the source signals a failure
is the function that's going to get executed in case the source signals a successful result
Given a side-effectful function that triggers an asynchronous computation,
execute it and return a Future reference.
The given register function will be invoked immediately to "schedule"
the asynchronous callback, where the callback is the parameter injected in
that function.
The register function can optionally return a ICancelable
reference that can get used to cancel the running asynchronous
computation.
Example:
import { Scheduler, Future, Try, Duration, Cancelable } from "funfix"
const delay = <A>(d: Duration, f: () => A, ec: Scheduler = Scheduler.global.get()) =>
Future.create<A>(
cb => {
const task = ec.scheduleOnce(d, () => cb(Try.of(f)))
return Cancelable.of(() => {
console.warn("Delayed task was cancelled")
task.cancel()
})
},
ec
)
Note that by not returning a cancelable, the returned Future reference
will NOT BE cancelable.
// This future is not cancelable, because we are not
// returning a cancelable reference
Future.create<number>(cb => {
setTimeout(1000, () => cb(Success(10)))
})
is the side-effectful function that will get invoked
to build our Future, receiving a callback that's supposed to
get invoked (only once) when the asynchronous computation completes,
and that can optionally return a cancelable reference that can
get used to cancel the running computation
is an optional Scheduler reference that will get used for scheduling the actual async execution; if one isn't provided then Scheduler.global gets used, which also allows for local overrides, being a DynamicRef
Returns a Future that will complete after the given delay.
This can be used to do delayed execution. For example:
Future.delayedTick(1000).flatMap(_ =>
Future.of(() => console.info("Hello!"))
)
is the duration to wait before signaling the tick
is the scheduler that will actually schedule the tick's execution
Creates a race condition between multiple futures, returning the result of the first one that completes, cancelling the rest.
const failure = Future.raise(new TimeoutError()).delayResult(2000)
// Will yield 1
const fa1 = Future.of(() => 1).delayResult(1000)
Future.firstCompletedOf([fa1, failure])
// Will yield a TimeoutError
const fa2 = Future.of(() => 1).delayResult(10000)
Future.firstCompletedOf([fa2, failure])
is the list of futures for which the race is started
is the scheduler doing the needed scheduling and error reporting
a future that will complete with the result of the first future form the list to complete, the rest being cancelled
Transforms any Promise-like data type into a Future.
const p: Promise<number> = Promise.resolve(10)
const f: Future<number> = Future.fromPromise(p)
is the promise reference that we want to convert into a Future
is an optional Scheduler reference that will get used for scheduling the actual async execution; if one isn't provided then Scheduler.global gets used, which also allows for local overrides, being a DynamicRef
Builds an already complete Future from a Try value.
import { Success, Failure, Future } from "funfix"
// Already completed with 1
const f1 = Future.fromTry(Success(1))
// Already completed in error
const f2 = Future.fromTry(Failure("err"))
is the Try value to stream in onComplete listeners
is an optional Scheduler reference that will get used for scheduling the actual async execution; if one isn't provided then Scheduler.global gets used, which also allows for local overrides, being a DynamicRef
Maps 2 Future values by the mapping function, returning a new
Future reference that completes with the result of mapping that
function to the successful values of the futures, or in failure in
case either of them fails.
This is a specialized Future.sequence operation and as such on cancellation or failure all future values get cancelled.
const fa1 = Future.of(() => 1)
const fa2 = Future.of(() => 2)
// Yields Success(3)
Future.map2(fa1, fa2, (a, b) => a + b)
// Yields Failure, because the second arg is a Failure
Future.map2(fa1, Future.raise("error"),
(a, b) => a + b
)
This operation is the Applicative.map2.
Maps 3 Future values by the mapping function, returning a new
Future reference that completes with the result of mapping that
function to the successful values of the futures, or in failure in
case either of them fails.
This is a specialized Future.sequence operation and as such on cancellation or failure all future values get cancelled.
const fa1 = Future.of(() => 1)
const fa2 = Future.of(() => 2)
const fa3 = Future.of(() => 3)
// Yields Success(6)
Future.map3(fa1, fa2, fa3, (a, b, c) => a + b + c)
// Yields Failure, because the second arg is a Failure
Future.map3(
fa1, fa2, Future.raise("error"),
(a, b, c) => a + b + c
)
This operation is the Applicative.map3.
Maps 4 Future values by the mapping function, returning a new
Future reference that completes with the result of mapping that
function to the successful values of the futures, or in failure in
case either of them fails.
This is a specialized Future.sequence operation and as such on cancellation or failure all future values get cancelled.
const fa1 = Future.of(() => 1)
const fa2 = Future.of(() => 2)
const fa3 = Future.of(() => 3)
const fa4 = Future.of(() => 4)
// Yields Success(10)
Future.map4(fa1, fa2, fa3, fa4, (a, b, c, d) => a + b + c + d)
// Yields Failure, because the second arg is a Failure
Future.map4(
fa1, fa2, fa3, Future.raise("error"),
(a, b, c, d) => a + b + c + d
)
This operation is the Applicative.map4.
Maps 5 Future values by the mapping function, returning a new
Future reference that completes with the result of mapping that
function to the successful values of the futures, or in failure in
case either of them fails.
This is a specialized Future.sequence operation and as such on cancellation or failure all future values get cancelled.
const fa1 = Future.of(() => 1)
const fa2 = Future.of(() => 2)
const fa3 = Future.of(() => 3)
const fa4 = Future.of(() => 4)
const fa5 = Future.of(() => 5)
// Yields Success(15)
Future.map5(fa1, fa2, fa3, fa4, fa5,
(a, b, c, d, e) => a + b + c + d + e
)
// Yields Failure, because the second arg is a Failure
Future.map5(
fa1, fa2, fa3, fa4, Future.raise("error"),
(a, b, c, d, e) => a + b + c + d + e
)
This operation is the Applicative.map5.
Maps 6 Future values by the mapping function, returning a new
Future reference that completes with the result of mapping that
function to the successful values of the futures, or in failure in
case either of them fails.
This is a specialized Future.sequence operation and as such on cancellation or failure all future values get cancelled.
const fa1 = Future.of(() => 1)
const fa2 = Future.of(() => 2)
const fa3 = Future.of(() => 3)
const fa4 = Future.of(() => 4)
const fa5 = Future.of(() => 5)
const fa6 = Future.of(() => 6)
// Yields Success(21)
Future.map6(
fa1, fa2, fa3, fa4, fa5, fa6,
(a, b, c, d, e, f) => a + b + c + d + e + f
)
// Yields Failure, because the second arg is a Failure
Future.map6(
fa1, fa2, fa3, fa4, fa5, Future.raise("error"),
(a, b, c, d, e, f) => a + b + c + d + e + f
)
This operation is the Applicative.map6.
Given a function that executes immediately, executes it asynchronously
and returns a Future that will complete when the result is ready.
const sum = (x: number, y: number) =>
Future.of(() => x + y)
is the function to execute asynchronously
is an optional Scheduler reference that will get used for scheduling the actual async execution; if one isn't provided then Scheduler.global gets used, which also allows for local overrides, being a DynamicRef
Lifts a pure value into the Future context, returning a Future
reference that's already complete with the given value.
This is the equivalent of Promise.resolve(a).
const f: Future<number> = Future.pure(10)
// Prints Success(10)
f.onComplete(r => console.info(r))
is the value to lift in the Future context and that will
get signaled in onComplete callbacks
is an optional Scheduler reference that will get used for scheduling the actual async execution; if one isn't provided then Scheduler.global gets used, which also allows for local overrides, being a DynamicRef
Lifts an error in the Future context, returning a Future reference
that's already failed with the given error.
This is the equivalent of Promise.reject.
const f: Future<number> = Future.raise("Oops!")
// Prints Failure("Oops!")
f.onComplete(r => console.info(r))
is the error to lift in the Future context and that will
get signaled as a failure in onComplete callbacks
is an optional Scheduler reference that will get used for scheduling the actual async execution; if one isn't provided then Scheduler.global gets used, which also allows for local overrides, being a DynamicRef
Asynchronously transforms a list of futures into a future of a list.
The equivalent of Promise.all, this is the specialized version of
Future.traverse.
Contract:
Iterable<Future<A>> list is eagerly evaluated, transformed
from the start into an Array<Future<A>>, so don't expect laziness in
evaluating itSample:
const f1 = Future.of(() => 1)
const f2 = Future.of(() => 2)
const f3 = Future.of(() => 3)
// Yields [1, 2, 3]
const all: Future<number[]> = Future.sequence([f1, f2, f3])
Keeps calling f until it returns a Right value.
Based on Phil Freeman's Stack Safety for Free.
const generate = () => {
const n = Math.random() * 1000
return n & n
}
// Keeps looping until an odd number is returned
Future.tailRecM(0, a => Future.of(() => {
return a % 2 == 0 ? Left(generate()) : Right(a)
})
is the initial seed
is the function that keeps being invoked with the previous
Left(a) value, until a Right(b) value is returned,
which will be the onComplete result of the Future
reference
is an optional Scheduler reference that will get used for scheduling the actual async execution; if one isn't provided then Scheduler.global gets used, which also allows for local overrides, being a DynamicRef
Given a list of items, builds future results out of it with the specified mapping function and returns a new future that's going to be completed with the list of all generated results.
This is the generic version of Future.sequence. Useful for
processing futures in parallel, with the parallelism factor being
configurable.
Example:
const list = [1, 2, 3, 4]
// Yields [2, 4, 6, 8]
Future.traverse(list)(a => Future.pure(a * 2))
// ... is equivalent to:
Future.sequence(list.map(_ => _ * 2))
Note that the given list is strictly processed, so no lazy behavior
should be expected if an Iterable is given.
But in comparison with Future.sequence, this builder has lazy
behavior in applying the given mapping function. Coupled with the
parallelism factor, this can be used to do batched processing:
const userIDs = [1, 2, 3, 4]
// Make at most 2 requests in parallel:
Future.traverse(userIDs, 2)(fetchUserDetails)
are the values that get fed in the generator function for building a list of future results
is the maximum number of futures that are going to
be processed in parallel, defaults to Infinity
is an optional scheduler that's going to be used for scheduling the needed asynchronous boundaries
a function that takes as parameter a the generator function that's
going to map the given list, transforming it into a list of
futures, finally returning a future that's going to complete
with the list of all asynchronously generated results
Generated using TypeDoc
Reference to the current ICancelable available for subsequent data transformations.
Protected, because it shouldn't be public API, being meant for
Futureimplementations.