Yet Another Reason Promise
This project has taken a lot of inspiration the future library. Also many bucklescript/reason Promise libraries exists. However this version focuses on the premise that a promise library should internally prepare for the possibility of failures -> thus Belt.Result.t is integral part of this library.
Install
npm install bs-yarp
And to your bsconfig.json
:
"bs-dependencies": [..., "bs-yarp", ...],
Safe to open the whole BsYarp, only singular Promise
module is imported:
open BsYarp;
Usage examples
Type:
Promise.t('a) /* Promise will resolve with ok-value ('a) or with error (exn) */
Create Promise
- From Js.Promise.t :
Promise.fromJs(jsPromise);
- From a value:
Promise.fromValue("example");
- The given value is internally set as Ok-value.
- From a
Belt.Result.t
value:Promise.fromResult(res);
- Internally set as Ok or Error -value depending on the given result.
- With
Promise.make
which uses resolve callback:
ThePromise.make(resolve => setTimeout(() => resolve(Result.Ok("example")), 500) -> ignore );
resolve
callback takes an argument of typeBelt.Result.t('a, exn)
- With
Promise.makeWithCb
which is more compatible with the node.js callback convention:type nodeCb('a, 'e) = (Js.Nullable.t('e), Js.Nullable.t('a)) => unit; [@bs.val] [@bs.module "fs"] external readFile: string => string => nodeCb('a, 'e) => unit = ""; Promise.makeWithCb(callback => readFile("example.txt", "utf8", callback));
- The error type is generic 'e here. The
makeWithCb
will auto-convert any kind of 'e into exn as long as the 'e can be inferred consistently into some type. This is similar to the way reason converts all kinds of errors thrown inside oftry()
into exn type.
- The error type is generic 'e here. The
- API section below contains type descriptions of all the functions.
Action and catch
promise
-> Promise.tapOk(value => Js.log("Example: " ++ value))
-> Promise.catch(e => Js.log("Error: " ++ Js.String.make(e)));
A common pattern where tapOk
executes the desired effects for the resolved value or alternatively
catch
is executed in case of error. The chain terminates with unit
(no additional ->ignore
needed to terminate the fast forward chain in this case)
Transformations
Promise.fromValue(123)
-> Promise.mapOk(v => (v + 45) * 3)
-> Promise.flatMapOk(v => fnReturningAPromise(v))
-> Promise.tapOk(x => Js.log(x))
-> Promise.toJs() /* to Js.Promise.t */
About Promise.toJs()
:
- Because Js.Promise.t is used underneath and it takes
exn
types of error values, it means that rejected promises will unavoidably have complex[["Test.SomeError",21],"example"]
types of contents in the js side which may seem confusing at first when e.g. logged to application logs.
API:
-
type:
t('a)
- This Promise type. Internal details encapsuled.
-
make: ((Result.t('a, exn) => unit) => unit) => t('a)
- Make new using resolver.
-
makeWithCb: (((Js.Nullable.t('e), Js.Nullable.t('a)) => unit) => unit) => t('a)
- Make new with a node callback.
-
fromValue: 'a => t('a)
- Make new from ok value. Immediately resolved.
-
fromError: exn => t('a)
- Make new from error value. Immediately resolved as error.
-
fromResult: Result.t('a, exn) => t('a)
- Make new from result. Immediately resolved as Ok or Error.
-
fromJs: Js.Promise.t('a) => t('a)
- Make new based on jsPromise. Resolves as Ok when the jsPromise is resolved or as Error if the JsPromise is rejected.
-
fromJsWithErrorConverter: Js.Promise.t('a) => (Js.Promise.error => exn) => t('a)
- Same as
fromJs
but you can provide custom error converter(Js.Promise.error => exn)
- Same as
-
toJs: t('a) => Js.Promise.t('a)
- Returns a jsPromise. If rejected, the ocaml error (always of type exn) is passed as is.
-
toJsWithErrorConversion: t('a) => Js.Promise.t('a)
- Returns a jsPromise. If rejected, the ocaml error is internally converted into a js Error (Js.Exn.t) on rejection.
-
tapResult: t('a) => (Result.t('a, exn) => unit) => t('a)
- With promise, execute the consumer with the internal result when it is resolved. Any exceptions thrown by consumer are ignored. Returns a promise which is identical to the given promise.
-
getResult: t('a) => (Result.t('a, exn) => unit) => unit
- Like
tapResult
but without return value.
- Like
-
tapOk: t('a) => ('a => unit) => t('a)
- With promise, execute the consumer with the resolved ok value. Any exceptions thrown by the consumer are ignored. Returns a promise which is identical to the given promise.
-
tapError: t('a) => (exn => unit) => t('a)
- Similar to
tapOk
, but error value is passed to the consumer.
- Similar to
-
catch: t('a) => (exn => unit) => unit
- Like
tapError
but without return value.
- Like
-
mapOk: t('a) => ('a => 'b) => t('b)
- With promise, map ok-value with the given function. Returned promise will either contain the new ok-value or an error value if the function throws an exception.
-
mapError: t('a) => (exn => exn) => t('a)
- With promise, map error-value with the given function. If the function throws an exception, that too is catched.
-
mapResult: t('a) => (Result.t('a, exn) => Result.t('b, exn)) => t('b)
- With promise, map Belt.Result.t into another Belt.Result.t. If function throws an exception it is mapped as Error result.
-
mapOkResult: t('a) => ('a => Result.t('b, exn)) => t('b)
- With promise, map ok value into Result.t. If function throws an exception it is mapped as Error result.
-
mapErrorResult: t('a) => (exn => Result.t('a, exn)) => t('a)
- With promise, map error into Result.t. If function throws an exception it is mapped as Error result.
-
flatMap: t('a) => (Result.t('a, exn) => t('b)) => t('b)
- With promise, bind the function which returns the resulting promise. No exception catching at this level.
-
flatMapOk: t('a) => ('a => t('b)) => t('b)
- With promise, bind ok value to the function which returns the resulting promise. No exception catching at this level.
-
flatMapError: t('a) => (exn => t('a)) => t('a)
- With promise, bind error value the function which returns the resulting promise. No exception catching at this level.
-
all: list(t('a)) => t(list('a))
- Turn list of promises (of homogeneous type) into a promise of list.
-
all2: (t('a), t('b)) => t(('a, 'b))
- Tuple of heterogeneous promises into a promise of tuple.
-
all3: (t('a), t('b), t('c)) => t(('a, 'b, 'c))
-
all4: (t('a), t('b), t('c), t('d)) => t(('a, 'b, 'c, 'd))
-
all5: (t('a), t('b), t('c), t('d), t('e)) => t(('a, 'b, 'c, 'd, 'e))
-
all6: (t('a), t('b), t('c), t('d), t('e), t('f)) => t(('a, 'b, 'c, 'd, 'e, 'f))
-
map2: t('a) => t('b) => ((Result.t('a, exn), Result.t('b, exn)) => Result.t('z, exn)) => t('z)
- map2 takes 3 arguments: 2 heterogeneous promises and a bi-function which combines results into a combined result. Returned promise will contain the combined result.
-
map3: t('a) => t('b) => t('c) => ((Result.t('a, exn), Result.t('b, exn), Result.t('c, exn)) => Result.t('z, exn)) => t('z)
-
map4: t('a) => t('b) => t('c) => t('d) => ((Result.t('a, exn), Result.t('b, exn), Result.t('c, exn), Result.t('d, exn)) => Result.t('z, exn)) => t('z)
-
map5: t('a) => t('b) => t('c) => t('d) => t('e) => ((Result.t('a, exn), Result.t('b, exn), Result.t('c, exn), Result.t('d, exn), Result.t('e, exn)) => Result.t('z, exn)) => t('z)
-
map6: t('a) => t('b) => t('c) => t('d) => t('e) => t('f) => ((Result.t('a, exn), Result.t('b, exn), Result.t('c, exn), Result.t('d, exn), Result.t('e, exn), Result.t('f, exn)) => Result.t('z, exn)) => t('z)