Skip to content

Commit

Permalink
Add more bindings to Promise utils (#204)
Browse files Browse the repository at this point in the history
* Add more bindings to Promise utils

* more accurate typename

* changelog
  • Loading branch information
cometkim authored Apr 2, 2024
1 parent 6725ea4 commit f700b44
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- BREAKING: Intl types: simplify bindings for constructors / functions with optional arguments. https://github.com/rescript-association/rescript-core/pull/198
- Fix: Expose Intl.Common. https://github.com/rescript-association/rescript-core/pull/197
- Add `Array.flatMapWithIndex` https://github.com/rescript-association/rescript-core/pull/199
- Add `Promise.any`, `Promise.allSettled`, `Promise.withResolvers` https://github.com/rescript-association/rescript-core/pull/204

## 1.1.0

Expand Down
65 changes: 64 additions & 1 deletion src/Core__Promise.res
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@ type t<+'a> = promise<'a>
@new
external make: (('a => unit, 'e => unit) => unit) => t<'a> = "Promise"

@val @scope("Promise")
type promiseAndResolvers<'a> = {
promise: t<'a>,
resolve: 'a => unit,
reject: exn => unit,
}

@scope("Promise") @val
external withResolvers: unit => promiseAndResolvers<_> = "withResolvers"

@scope("Promise") @val
external resolve: 'a => t<'a> = "resolve"

@send external then: (t<'a>, 'a => t<'b>) => t<'b> = "then"
Expand Down Expand Up @@ -34,6 +43,57 @@ external all5: ((t<'a>, t<'b>, t<'c>, t<'d>, t<'e>)) => t<('a, 'b, 'c, 'd, 'e)>
@scope("Promise") @val
external all6: ((t<'a>, t<'b>, t<'c>, t<'d>, t<'e>, t<'f>)) => t<('a, 'b, 'c, 'd, 'e, 'f)> = "all"

@tag("status")
type settledResult<+'a> =
| @as("fulfilled") Fulfilled({value: 'a}) | @as("rejected") Rejected({reason: exn})

@scope("Promise") @val
external allSettled: array<promise<'a>> => promise<array<settledResult<'a>>> = "allSettled"

@scope("Promise") @val
external allSettled2: ((promise<'a0>, promise<'a1>)) => promise<(
settledResult<'a0>,
settledResult<'a1>,
)> = "allSettled"

@scope("Promise") @val
external allSettled3: ((promise<'a0>, promise<'a1>, promise<'a2>)) => promise<(
settledResult<'a0>,
settledResult<'a1>,
settledResult<'a2>,
)> = "allSettled"

@scope("Promise") @val
external allSettled4: ((promise<'a0>, promise<'a1>, promise<'a2>, promise<'a3>)) => promise<(
settledResult<'a0>,
settledResult<'a1>,
settledResult<'a2>,
settledResult<'a3>,
)> = "allSettled"

@scope("Promise") @val
external allSettled5: (
(promise<'a0>, promise<'a1>, promise<'a2>, promise<'a3>, promise<'a4>)
) => promise<(
settledResult<'a0>,
settledResult<'a1>,
settledResult<'a2>,
settledResult<'a3>,
settledResult<'a4>,
)> = "allSettled"

@scope("Promise") @val
external allSettled6: (
(promise<'a0>, promise<'a1>, promise<'a2>, promise<'a3>, promise<'a4>, promise<'a5>)
) => promise<(
settledResult<'a0>,
settledResult<'a1>,
settledResult<'a2>,
settledResult<'a3>,
settledResult<'a4>,
settledResult<'a5>,
)> = "allSettled"

@send
external _catch: (t<'a>, exn => t<'a>) => t<'a> = "catch"

Expand All @@ -46,4 +106,7 @@ let catch = (promise: promise<'a>, callback: exn => promise<'a>): promise<'a> =>
@scope("Promise") @val
external race: array<t<'a>> => t<'a> = "race"

@scope("Promise") @val
external any: array<t<'a>> => t<'a> = "any"

external done: promise<'a> => unit = "%ignore"
154 changes: 151 additions & 3 deletions src/Core__Promise.resi
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,37 @@ Promise.make((resolve, reject) => {
@new
external make: (('a => unit, 'e => unit) => unit) => t<'a> = "Promise"

type promiseAndResolvers<'a> = {
promise: t<'a>,
resolve: 'a => unit,
reject: exn => unit,
}

/**
`withResolvers()` returns a object containing a new promise with functions to resolve or reject it. See [`Promise.withResolvers`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers) on MDN.
## Examples
```rescript
open Promise
let {promise, resolve, _} = Promise.withResolvers()
setTimeout(() => {
resolve(. "success")
}, 1000)->ignore
promise
->thenResolve(str => {
Console.log(str)
})
->ignore
```
*/
@scope("Promise")
@val
external withResolvers: unit => promiseAndResolvers<_> = "withResolvers"

/**
`catch(promise, errorCallback)` registers an exception handler in a promise chain.
The `errorCallback` receives an `exn` value that can later be refined into a JS
Expand Down Expand Up @@ -206,7 +237,7 @@ resolve(5)
external finally: (t<'a>, unit => unit) => t<'a> = "finally"

/**
`race(arr)` combining `array` of promises. See [`Promise.race`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race) on MDN.
`race(arr)` runs all promises concurrently and returns promise settles with the eventual state of the first promise that settles. See [`Promise.race`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race) on MDN.
## Examples
Expand All @@ -233,8 +264,34 @@ race(promises)->then(winner => {
external race: array<t<'a>> => t<'a> = "race"

/**
`all(promises)` runs all promises in parallel and returns a new promise resolving
all gathered results in a unified array. See [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) on MDN.
`any(arr)` runs all promises concurrently and returns promise fulfills when any of the input's promises fulfills, with this first fulfillment value. See [`Promise.any`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any) on MDN.
## Examples
```rescript
open Promise
let racer = (ms, name) => {
Promise.make((resolve, _) => {
setTimeout(() => {
resolve(name)
}, ms)->ignore
})
}
let promises = [racer(1000, "Turtle"), racer(500, "Hare"), racer(100, "Eagle")]
any(promises)->then(winner => {
Console.log("The winner is " ++ winner)
resolve()
})
```
*/
@scope("Promise")
@val
external any: array<t<'a>> => t<'a> = "any"

/**
`all(promises)` runs all promises concurrently and returns a promise fulfills when all of the input's promises fulfill, with an array of the fulfillment values. See [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) on MDN.
```rescript
open Promise
Expand Down Expand Up @@ -290,6 +347,97 @@ external all5: ((t<'a>, t<'b>, t<'c>, t<'d>, t<'e>)) => t<('a, 'b, 'c, 'd, 'e)>
@val
external all6: ((t<'a>, t<'b>, t<'c>, t<'d>, t<'e>, t<'f>)) => t<('a, 'b, 'c, 'd, 'e, 'f)> = "all"

@tag("status")
type settledResult<+'a> =
| @as("fulfilled") Fulfilled({value: 'a}) | @as("rejected") Rejected({reason: exn})

/**
`allSettled(promises)` runs all promises concurrently and returns promise fulfills when all of the input's promises settle with an array of objects that describe the outcome of each promise. See [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) on MDN.
```rescript
open Promise
exception TestError(string)
let promises = [resolve(1), resolve(2), reject(TestError("some rejected promise"))]
allSettled(promises)
->then((results) => {
results->Array.forEach((result) => {
switch result {
| Fulfilled({value: num}) =>
Console.log2("Number: ", num)
| Rejected({reason}) =>
Console.log(reason)
}
})
resolve()
})
->ignore
```
*/
@scope("Promise")
@val
external allSettled: array<t<'a>> => t<array<settledResult<'a>>> = "allSettled"

/**
`allSettled2((p1, p2))`. Like `allSettled()`, but with a fixed size tuple of 2
*/
@scope("Promise")
@val
external allSettled2: ((t<'a>, t<'b>)) => t<(settledResult<'a>, settledResult<'b>)> = "allSettled"

/**
`allSettled3((p1, p2, p3))`. Like `allSettled()`, but with a fixed size tuple of 3
*/
@scope("Promise")
@val
external allSettled3: ((t<'a>, t<'b>, t<'c>)) => t<(
settledResult<'a>,
settledResult<'b>,
settledResult<'c>,
)> = "allSettled"

/**
`allSettled4((p1, p2, p3, p4))`. Like `allSettled()`, but with a fixed size tuple of 4
*/
@scope("Promise")
@val
external allSettled4: ((t<'a>, t<'b>, t<'c>, t<'d>)) => t<(
settledResult<'a>,
settledResult<'b>,
settledResult<'c>,
settledResult<'d>,
)> = "allSettled"

/**
`allSettled5((p1, p2, p3, p4, p5))`. Like `allSettled()`, but with a fixed size tuple of 5
*/
@scope("Promise")
@val
external allSettled5: ((t<'a>, t<'b>, t<'c>, t<'d>, t<'e>)) => t<(
settledResult<'a>,
settledResult<'b>,
settledResult<'c>,
settledResult<'d>,
settledResult<'e>,
)> = "allSettled"

/**
`allSettled6((p1, p2, p4, p5, p6))`. Like `allSettled()`, but with a fixed size tuple of 6
")*/
@scope("Promise")
@val
external allSettled6: ((t<'a>, t<'b>, t<'c>, t<'d>, t<'e>, t<'f>)) => t<(
settledResult<'a>,
settledResult<'b>,
settledResult<'c>,
settledResult<'d>,
settledResult<'e>,
settledResult<'f>,
)> = "allSettled"

/**
`done(p)` is a safe way to ignore a promise. If a value is anything else than a
promise, it will raise a type error.
Expand Down

0 comments on commit f700b44

Please sign in to comment.