purescript-js-promise-aff

November 9, 2022 ยท View on GitHub

Latest release Build status Pursuit

Simple library for interop between Aff and JavaScript promises.

No typeclass instances etc are provided to use Promises directly - the intention is that your PureScript code uses Aff internally, and is only wrapped as a Promise to present an API for consumption in JavaScript code (and vice versa).

Exposing promises: Aff to Promise

The origin of this library was to solve the following problem: I want to write asynchronous code in Aff, but I need to expose this as an API to JavaScript in the form of a Promise.

Therefore the majority of code can be written to return an Aff, in this example using readTextFile from purescript-node-fs-aff:

getLinesAff :: Aff (Array String)
getLinesAff = do
  text <- readTextFile Encoding.UTF8 "data.txt"
  pure $ split (Pattern "\n") text

and this can be exposed as a function returning a promise:

import Promise.Aff as Promise

getLines :: Effect (Promise (Array String))
getLines = Promise.fromAff getLinesAff

This function returns an Effect beause a promise is "already running". A JavaScript function consuming this API would just call getLines().then(...).

Consuming promises: Promise to Aff

The reverse problem occurs when wrapping a JS library that uses promises for asynchronous behaviour (Aff comes with a perfectly good function to deal with consuming libraries that use callbacks).

Consider the case of consuming the fetch API.

exports.fetchImpl = function (url) {
  return function() {
    return fetch(url);
  };
}
foreign import data Response :: Type
foreign import fetchImpl :: String -> Effect (Promise Response)

Notice that the fetch(url) call is wrapped in a thunk and imported as an Effect, because otherwise the fetch operation would be initiated as a side-effect of a pure function - while fetch returns a promise, at the point the function returns the network request has already been initated.

The response can then be converted to an Aff and consumed easily:

import Promise.Aff as Promise

fetch :: String -> Aff String
fetch = fetchImpl >>> Promise.toAffE

Documentation

API documentation is available on Pursuit.