
The Future is Now
Future is a lightweight, functional alternative to Js.Promise
for ReScript, designed to make async code more composable and maintainable.
Compatibility
- Use
reason-future@2.6.0
for ReasonML or ReScript ≤ v10. - Use
reason-future@3.0.0
for ReScript ≥ v11.
Key Benefits of Using Future Over Promises:
- Lighter weight – Only ~25 lines of implementation.
- Simpler – Futures only resolve to a single type (as opposed to resolve and reject types), giving you more flexibility on your error handling.
- More robust – Futures have sound typing (unlike JS promises).
Installation
First make sure you have rescript >= 11.1.X
. Then install with npm:
$ npm install --save reason-future
Then add "reason-future"
to your rescript.json
dev dependencies:
{
...
"bs-dependencies": [
"reason-future"
]
}
Basic Usage
To create a task, use Future.make
. It provides a single resolve
function, similar to how Promises work but without a reject
:
let futureGreeting = Future.make(resolve => resolve("hi"));
To get the value of a future, use Future.get
:
let futureGreeting = Future.make(resolve => resolve("hi"));
futureGreeting->Future.get(x => Js.log("Got value: " ++ x));
Future.make(resolve => resolve("hi"))
->Future.get(x => Js.log("Got value: " ++ x));
Future.get
only retrieves the future value. If you want to transform it to a different value, then you should use Future.map
:
let future_A = Future.value(99);
let future_B = future_A->Future.map(n => n + 1);
future_A->Future.get(n => Js.log(n));
future_B->Future.get(n => Js.log(n));
And finally, if you map
a future and return another future, you probably want to flatMap
instead:
let futureNum = Future.value(50);
let ft_a = futureNum->Future.map(n => Future.value(n + 10));
let ft_b = futureNum->Future.flatMap(n => Future.value(n + 20));
API
Core functions. Note: _
represents the future itself as inserted by ->
(the pipe operator).
Future.make(resolver)
- Create a new, potentially-async future.Future.value(x)
- Create a new future with a plain value (synchronous).Future.map(_,fn)
- Transform a future value into another valueFuture.flatMap(_,fn)
- Transform a future value into another future valueFuture.get(_,fn)
- Get the value of a futureFuture.tap(_,fn)
- Do something with the value of a future without changing it. Returns the same future so you can continue using it in a pipeline. Convenient for side effects such as console logging.Future.all(_,fn)
- Turn a list of futures into a future of a list. Used when you want to wait for a collection of futures to complete before doing something (equivalent to Promise.all in Javascript).
Result
Convenience functions when working with a future Result
. Note: _
represents the future itself as inserted by ->
(the pipe operator).
Note 2: The terms Result.Ok
and Result.Error
in this context are expected to be read as Ok
and Error
.
Future.mapOk(_,fn)
- Transform a future value into another value, but only if the value is an Result.Ok
. Similar to Promise.prototype.then
Future.mapError(_,fn)
- Transform a future value into another value, but only if the value is an Result.Error
. Similar to Promise.prototype.catch
Future.tapOk(_,fn)
- Do something with the value of a future without changing it, but only if the value is a Ok
. Returns the same future. Convenience for side effects such as console logging.Future.tapError(_,fn)
- Same as tapOk
but for Result.Error
The following are more situational:
Future.flatMapOk(_, fn)
- Transform a future Result.Ok
into
a future Result
. Flattens the inner future.Future.flatMapError(_, fn)
- Transform a future Result.Error
into
a future Result
. Flattens the inner future.
FutureJs
Convenience functions for interop with JavaScript land.
FutureJs.fromPromise(promise, errorTransformer)
promise
is the RescriptCore.Promise.t('a)
that will be transformed into a
Future.t(result('a, 'e))
errorTransformer
allows you to determine how Promise.error
objects will be transformed before they are returned wrapped within
a Error
. This allows you to implement the error handling
method which best meets your application's needs.
FutureJs.toPromise(future)
future
is any Future.t('a)
which is transformed into a
RescriptCore.Promise.t('a)
. Always resolves, never rejects the promise.
FutureJs.resultToPromise(future)
future
is the Future.t(result('a, 'e))
which is transformed into a
RescriptCore.Promise.t('a)
. Resolves the promise on Ok result and rejects on Error result.
Example use:
let handleError = Js.String.make;
somePromiseGetter()
->FutureJs.fromPromise(handleError)
->Future.tap(value => Js.log2("It worked!", value))
->Future.tapError(err => Js.log2("uh on", err));
See Composible Error Handling in OCaml for several strategies that you may employ.
Stack Safety
By default this library is not stack safe, you will recieve a 'Maximum call stack size exceeded' error if you recurse too deeply. You can opt into stack safety by passing an optional parameter to the constructors of trampoline. This has a slight overhead. For example:
let stackSafe = Future.make(~executor=`trampoline, resolver);
let stackSafeValue = Future.value(~executor=`trampoline, "Value");
TODO
Build
npm run build
Build + Watch
npm run start
Test
npm test
Editor
If you use vscode
, Press Windows + Shift + B
it will build automatically