Skip to content

Instantly share code, notes, and snippets.

@tomquas
Forked from lilactown/promises.re
Created February 9, 2018 08:01
Show Gist options
  • Select an option

  • Save tomquas/c0558728e7a89d414df500952aacaabc to your computer and use it in GitHub Desktop.

Select an option

Save tomquas/c0558728e7a89d414df500952aacaabc to your computer and use it in GitHub Desktop.

Revisions

  1. @lilactown lilactown revised this gist Dec 2, 2017. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion promises.re
    Original file line number Diff line number Diff line change
    @@ -37,7 +37,9 @@ Js.Promise.resolve(1)

    /* And even better with some Reason spice */
    Js.Promise.(
    resolve(1) |> then_((value) => resolve(value + 1)) |> then_((value) => resolve(Js.log(value)))
    resolve(1)
    |> then_((value) => resolve(value + 1))
    |> then_((value) => resolve(Js.log(value)))
    );

    /* Waiting for two values */
  2. @lilactown lilactown revised this gist Dec 2, 2017. 1 changed file with 46 additions and 52 deletions.
    98 changes: 46 additions & 52 deletions promises.re
    Original file line number Diff line number Diff line change
    @@ -1,20 +1,18 @@
    /**
    * Making promises
    */
    let okPromise = Js.Promise.make (fun ::resolve reject::_ => resolve "ok" [@bs]);
    let okPromise = Js.Promise.make((~resolve, ~reject as _) => [@bs] resolve("ok"));

    /* Simpler promise creation for static values */
    Js.Promise.resolve "easy";
    Js.Promise.resolve("easy");

    Js.Promise.reject (Invalid_argument "too easy");
    Js.Promise.reject(Invalid_argument("too easy"));

    /* Create a promise that resolves much later */
    let timer =
    Js.Promise.make (
    fun ::resolve reject::_ => {
    /* `ignore` returns `unit`; it's just to get rid of compiler warning about
    unassigned expressions not returning `unit` */
    ignore (Js.Global.setTimeout (fun () => resolve "Done!" [@bs]) 1000);
    Js.Promise.make(
    (~resolve, ~reject as _) => {
    ignore(Js.Global.setTimeout(() => [@bs] resolve("Done!"), 1000));
    ()
    }
    );
    @@ -24,49 +22,45 @@ let timer =
    * Handling promise values
    * Note that we *have* to return a new promise inside of the callback given to then_;
    */
    Js.Promise.then_ (fun value => Js.Promise.resolve (Js.log value)) okPromise;
    Js.Promise.then_((value) => Js.Promise.resolve(Js.log(value)), okPromise);

    /* Chaining */
    Js.Promise.then_
    (fun value => Js.Promise.resolve (Js.log value))
    (Js.Promise.then_ (fun value => Js.Promise.resolve (value + 1)) (Js.Promise.resolve 1));
    Js.Promise.then_(
    (value) => Js.Promise.resolve(Js.log(value)),
    Js.Promise.then_((value) => Js.Promise.resolve(value + 1), Js.Promise.resolve(1))
    );

    /* Better with pipes 😉 */
    Js.Promise.resolve 1
    |> Js.Promise.then_ (fun value => Js.Promise.resolve (value + 1))
    |> Js.Promise.then_ (fun value => Js.Promise.resolve (Js.log value));
    Js.Promise.resolve(1)
    |> Js.Promise.then_((value) => Js.Promise.resolve(value + 1))
    |> Js.Promise.then_((value) => Js.Promise.resolve(Js.log(value)));

    /* And even better with some Reason spice */
    Js.Promise.(
    resolve 1
    |> then_ (fun value => resolve (value + 1))
    |> then_ (fun value => resolve (Js.log value))
    resolve(1) |> then_((value) => resolve(value + 1)) |> then_((value) => resolve(Js.log(value)))
    );

    /* Waiting for two values */
    Js.Promise.(
    all2 (resolve 1, resolve "a")
    |> then_ (
    fun (v1, v2) => {
    Js.log ("Value 1: " ^ string_of_int v1);
    Js.log ("Value 2: " ^ v2);
    resolve ()
    all2((resolve(1), resolve("a")))
    |> then_(
    ((v1, v2)) => {
    Js.log("Value 1: " ++ string_of_int(v1));
    Js.log("Value 2: " ++ v2);
    resolve()
    }
    )
    );

    /* Waiting for an array of values */
    Js.Promise.(
    all [|resolve 1, resolve 2, resolve 3|]
    |> then_ (
    /* This is actually a cheat of Reason/OCaml's pattern matching syntax;
    We know that this is exhaustive, but the compiler will complain.
    Use at own risk 🤠 */
    fun [|v1, v2, v3|] => {
    Js.log ("Value 1: " ^ string_of_int v1);
    Js.log ("Value 2: " ^ string_of_int v2);
    Js.log ("Value 3: " ^ string_of_int v3);
    resolve ()
    all([|resolve(1), resolve(2), resolve(3)|])
    |> then_(
    ([|v1, v2, v3|]) => {
    Js.log("Value 1: " ++ string_of_int(v1));
    Js.log("Value 2: " ++ string_of_int(v2));
    Js.log("Value 3: " ++ string_of_int(v3));
    resolve()
    }
    )
    );
    @@ -76,17 +70,17 @@ Js.Promise.(
    * Error handling
    */
    /* Using a built-in OCaml error */
    let notFoundPromise = Js.Promise.make (fun resolve::_ ::reject => reject Not_found [@bs]);
    let notFoundPromise = Js.Promise.make((~resolve as _, ~reject) => [@bs] reject(Not_found));

    Js.Promise.then_ (fun value => Js.Promise.resolve (Js.log value)) notFoundPromise
    |> Js.Promise.catch (fun err => Js.Promise.resolve (Js.log err));
    Js.Promise.then_((value) => Js.Promise.resolve(Js.log(value)), notFoundPromise)
    |> Js.Promise.catch((err) => Js.Promise.resolve(Js.log(err)));

    /* Using a custom error */
    exception Oh_no string;
    exception Oh_no(string);

    let ohNoPromise = Js.Promise.make (fun resolve::_ ::reject => reject (Oh_no "oh no") [@bs]);
    let ohNoPromise = Js.Promise.make((~resolve as _, ~reject) => [@bs] reject(Oh_no("oh no")));

    Js.Promise.catch (fun err => Js.Promise.resolve (Js.log err)) ohNoPromise;
    Js.Promise.catch((err) => Js.Promise.resolve(Js.log(err)), ohNoPromise);


    /**
    @@ -96,35 +90,35 @@ Js.Promise.catch (fun err => Js.Promise.resolve (Js.log err)) ohNoPromise;
    * it's much better to use a `result` type instead.
    */
    let betterOk =
    Js.Promise.make (fun ::resolve reject::_ => resolve (Js.Result.Ok "everything's fine") [@bs]);
    Js.Promise.make((~resolve, ~reject as _) => [@bs] resolve(Js.Result.Ok("everything's fine")));

    let betterOhNo =
    Js.Promise.make (fun ::resolve reject::_ => resolve (Js.Result.Error "nope nope nope") [@bs]);
    Js.Promise.make((~resolve, ~reject as _) => [@bs] resolve(Js.Result.Error("nope nope nope")));

    let handleResult =
    Js.Promise.then_ (
    fun result =>
    Js.Promise.resolve (
    Js.Promise.then_(
    (result) =>
    Js.Promise.resolve(
    switch result {
    | Js.Result.Ok text => Js.log ("OK: " ^ text)
    | Js.Result.Error reason => Js.log ("Oh no: " ^ reason)
    | Js.Result.Ok(text) => Js.log("OK: " ++ text)
    | Js.Result.Error(reason) => Js.log("Oh no: " ++ reason)
    }
    )
    );

    handleResult betterOk;
    handleResult(betterOk);

    handleResult betterOhNo;
    handleResult(betterOhNo);


    /**
    * "Better living through functions."
    * This section is for collecting useful helper functions when handling promises
    */
    /* Get rid of the need for returning a promise every time we use `then_` */
    let thenResolve fn => Js.Promise.then_ (fun value => Js.Promise.resolve (fn value));
    let thenResolve = (fn) => Js.Promise.then_((value) => Js.Promise.resolve(fn(value)));

    Js.Promise.(resolve 1 |> thenResolve (fun value => value + 1) |> thenResolve Js.log);
    Js.Promise.(resolve(1) |> thenResolve((value) => value + 1) |> thenResolve(Js.log));

    /* Get rid of pesky compiler warnings at the end of a side-effectful promise chain */
    let thenIgnore fn p => thenResolve (fun value => fn value) p |> ignore;
    let thenIgnore = (fn, p) => thenResolve((value) => fn(value), p) |> ignore;
  3. @lilactown lilactown revised this gist Sep 26, 2017. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion promises.re
    Original file line number Diff line number Diff line change
    @@ -59,7 +59,8 @@ Js.Promise.(
    Js.Promise.(
    all [|resolve 1, resolve 2, resolve 3|]
    |> then_ (
    /* This is actually a huge cheat of Reason/OCaml's pattern matching syntax;
    /* This is actually a cheat of Reason/OCaml's pattern matching syntax;
    We know that this is exhaustive, but the compiler will complain.
    Use at own risk 🤠 */
    fun [|v1, v2, v3|] => {
    Js.log ("Value 1: " ^ string_of_int v1);
  4. @lilactown lilactown revised this gist Sep 19, 2017. 1 changed file with 32 additions and 2 deletions.
    34 changes: 32 additions & 2 deletions promises.re
    Original file line number Diff line number Diff line change
    @@ -43,6 +43,33 @@ Js.Promise.(
    |> then_ (fun value => resolve (Js.log value))
    );

    /* Waiting for two values */
    Js.Promise.(
    all2 (resolve 1, resolve "a")
    |> then_ (
    fun (v1, v2) => {
    Js.log ("Value 1: " ^ string_of_int v1);
    Js.log ("Value 2: " ^ v2);
    resolve ()
    }
    )
    );

    /* Waiting for an array of values */
    Js.Promise.(
    all [|resolve 1, resolve 2, resolve 3|]
    |> then_ (
    /* This is actually a huge cheat of Reason/OCaml's pattern matching syntax;
    Use at own risk 🤠 */
    fun [|v1, v2, v3|] => {
    Js.log ("Value 1: " ^ string_of_int v1);
    Js.log ("Value 2: " ^ string_of_int v2);
    Js.log ("Value 3: " ^ string_of_int v3);
    resolve ()
    }
    )
    );


    /**
    * Error handling
    @@ -94,6 +121,9 @@ handleResult betterOhNo;
    * This section is for collecting useful helper functions when handling promises
    */
    /* Get rid of the need for returning a promise every time we use `then_` */
    let thenDo fn => Js.Promise.then_ (fun value => Js.Promise.resolve (fn value));
    let thenResolve fn => Js.Promise.then_ (fun value => Js.Promise.resolve (fn value));

    Js.Promise.(resolve 1 |> thenResolve (fun value => value + 1) |> thenResolve Js.log);

    Js.Promise.(resolve 1 |> thenDo (fun value => value + 1) |> thenDo Js.log);
    /* Get rid of pesky compiler warnings at the end of a side-effectful promise chain */
    let thenIgnore fn p => thenResolve (fun value => fn value) p |> ignore;
  5. @lilactown lilactown revised this gist Sep 19, 2017. 1 changed file with 98 additions and 5 deletions.
    103 changes: 98 additions & 5 deletions promises.re
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,99 @@
    /* Making promises */
    let promise = Js.Promise.make (fun ::resolve ::reject => resolve "OK!" [@bs]);
    /**
    * Making promises
    */
    let okPromise = Js.Promise.make (fun ::resolve reject::_ => resolve "ok" [@bs]);

    /* Operating on promises */
    Js.Promise.then_ (fun result => Js.log result);
    /*Js.Promise.catch*/
    /* Simpler promise creation for static values */
    Js.Promise.resolve "easy";

    Js.Promise.reject (Invalid_argument "too easy");

    /* Create a promise that resolves much later */
    let timer =
    Js.Promise.make (
    fun ::resolve reject::_ => {
    /* `ignore` returns `unit`; it's just to get rid of compiler warning about
    unassigned expressions not returning `unit` */
    ignore (Js.Global.setTimeout (fun () => resolve "Done!" [@bs]) 1000);
    ()
    }
    );


    /**
    * Handling promise values
    * Note that we *have* to return a new promise inside of the callback given to then_;
    */
    Js.Promise.then_ (fun value => Js.Promise.resolve (Js.log value)) okPromise;

    /* Chaining */
    Js.Promise.then_
    (fun value => Js.Promise.resolve (Js.log value))
    (Js.Promise.then_ (fun value => Js.Promise.resolve (value + 1)) (Js.Promise.resolve 1));

    /* Better with pipes 😉 */
    Js.Promise.resolve 1
    |> Js.Promise.then_ (fun value => Js.Promise.resolve (value + 1))
    |> Js.Promise.then_ (fun value => Js.Promise.resolve (Js.log value));

    /* And even better with some Reason spice */
    Js.Promise.(
    resolve 1
    |> then_ (fun value => resolve (value + 1))
    |> then_ (fun value => resolve (Js.log value))
    );


    /**
    * Error handling
    */
    /* Using a built-in OCaml error */
    let notFoundPromise = Js.Promise.make (fun resolve::_ ::reject => reject Not_found [@bs]);

    Js.Promise.then_ (fun value => Js.Promise.resolve (Js.log value)) notFoundPromise
    |> Js.Promise.catch (fun err => Js.Promise.resolve (Js.log err));

    /* Using a custom error */
    exception Oh_no string;

    let ohNoPromise = Js.Promise.make (fun resolve::_ ::reject => reject (Oh_no "oh no") [@bs]);

    Js.Promise.catch (fun err => Js.Promise.resolve (Js.log err)) ohNoPromise;


    /**
    * Unfortunately, as one can see - catch expects a very generic `Js.Promise.error` value
    * that doesn't give us much to do with.
    * In general, we should not rely on rejecting/catching errors for control flow;
    * it's much better to use a `result` type instead.
    */
    let betterOk =
    Js.Promise.make (fun ::resolve reject::_ => resolve (Js.Result.Ok "everything's fine") [@bs]);

    let betterOhNo =
    Js.Promise.make (fun ::resolve reject::_ => resolve (Js.Result.Error "nope nope nope") [@bs]);

    let handleResult =
    Js.Promise.then_ (
    fun result =>
    Js.Promise.resolve (
    switch result {
    | Js.Result.Ok text => Js.log ("OK: " ^ text)
    | Js.Result.Error reason => Js.log ("Oh no: " ^ reason)
    }
    )
    );

    handleResult betterOk;

    handleResult betterOhNo;


    /**
    * "Better living through functions."
    * This section is for collecting useful helper functions when handling promises
    */
    /* Get rid of the need for returning a promise every time we use `then_` */
    let thenDo fn => Js.Promise.then_ (fun value => Js.Promise.resolve (fn value));

    Js.Promise.(resolve 1 |> thenDo (fun value => value + 1) |> thenDo Js.log);
  6. @lilactown lilactown created this gist Sep 17, 2017.
    6 changes: 6 additions & 0 deletions promises.re
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,6 @@
    /* Making promises */
    let promise = Js.Promise.make (fun ::resolve ::reject => resolve "OK!" [@bs]);

    /* Operating on promises */
    Js.Promise.then_ (fun result => Js.log result);
    /*Js.Promise.catch*/