Promise
Note: Starting from ReScript 10.1 and above, we recommend using async / await when interacting with Promises.
promise
type
Since 10.1
In ReScript, every JS promise is represented with the globally available promise<'a>
type. For ReScript versions < 10.1, use its original alias Js.Promise.t<'a>
instead.
Here's a usage example in a function signature:
RESI// User.resi file
type user = {name: string}
let fetchUser: string => promise<user>
To work with promise values (instead of using async
/ await
) you may want to use the built-in Promise
module.
Promise
A builtin module to create, chain and manipulate promises.
Creating a promise
RESlet p1 = Promise.make((resolve, reject) => {
// We use uncurried functions for resolve / reject
// for cleaner JS output without unintended curry calls
resolve("hello world")
})
let p2 = Promise.resolve("some value")
// You can only reject `exn` values for streamlined catch handling
exception MyOwnError(string)
let p3 = Promise.reject(MyOwnError("some rejection"))
Access the contents and transform a promise
RESlet logAsyncMessage = () => {
open Promise
Promise.resolve("hello world")
->then(msg => {
// then callbacks require the result to be resolved explicitly
resolve("Message: " ++ msg)
})
->then(msg => {
Console.log(msg)
// Even if there is no result, we need to use resolve() to return a promise
resolve()
})
->ignore // Requires ignoring due to unhandled return value
}
For comparison, the async
/ await
version of the same code would look like this:
RESlet logAsyncMessage = async () => {
let msg = await Promise.resolve("hello world")
Console.log(`Message: ${msg}`)
}
Needless to say, the async / await version offers better ergonomics and less opportunities to run into type issues.
Handling Rejected Promises
You can handle a rejected promise using the Promise.catch()
method, which allows you to catch and manage errors effectively.
Run multiple promises in parallel
In case you want to launch multiple promises in parallel, use Promise.all
:
Js.Promise module (legacy - do not use)
Note: The
Js.Promise
bindings are following the outdated data-last convention from a few years ago. We kept those APIs for backwards compatibility. Either usePromise
or a third-party promise binding instead.
ReScript has built-in support for JavaScript promises. The 3 functions you generally need are:
Js.Promise.resolve: 'a => Js.Promise.t<'a>
Js.Promise.then_: ('a => Js.Promise.t<'b>, Js.Promise.t<'a>) => Js.Promise.t<'b>
Js.Promise.catch: (Js.Promise.error => Js.Promise.t<'a>, Js.Promise.t<'a>) => Js.Promise.t<'a>
Additionally, here's the type signature for creating a promise on the ReScript side:
RESJs.Promise.make: (
(
~resolve: (. 'a) => unit,
~reject: (. exn) => unit
) => unit
) => Js.Promise.t<'a>
This type signature means that make
takes a callback that takes 2 named arguments, resolve
and reject
. Both arguments are themselves uncurried callbacks (with a dot). make
returns the created promise.
Usage
Using the pipe operator:
let myPromise = Js.Promise.make((~resolve, ~reject) => resolve(. 2))
myPromise->Js.Promise.then_(value => {
Console.log(value)
Js.Promise.resolve(value + 2)
}, _)->Js.Promise.then_(value => {
Console.log(value)
Js.Promise.resolve(value + 3)
}, _)->Js.Promise.catch(err => {
Console.log2("Failure!!", err)
Js.Promise.resolve(-2)
}, _)