Skip to content

Instantly share code, notes, and snippets.

@ehpc
Last active July 17, 2023 03:29
Show Gist options
  • Save ehpc/2a524b78729ee6b4e8111f89c66d7ff5 to your computer and use it in GitHub Desktop.
Save ehpc/2a524b78729ee6b4e8111f89c66d7ff5 to your computer and use it in GitHub Desktop.
How to compose promises with Ramda
// Custom promise-based compose
const composeWithPromise = (...args) =>
R.composeWith((f, val) => {
if (val && val.then) {
return val.then(f);
}
if (Array.isArray(val) && val.length && val[0] && val[0].then) {
return Promise.all(val).then(f);
}
return f(val);
})(args);
/**************************/
/******** EXAMPLE *********/
/**************************/
const getRandomLimit = (min, max) => Math.random() * (max - min) + min;
const fetchPokemonList = limit => {
return fetch(`https://pokeapi.co/api/v2/pokemon?limit=${limit}`).then(r =>
r.json()
);
};
const fetchPokemon = name => {
return fetch(`https://pokeapi.co/api/v2/pokemon/${name}/`).then(r => {
return r.json();
// Uncomment the line below to see error handling
// throw new Error("Simulated error");
});
};
const cleanupPokemonData = data => ({
id: data.id,
name: data.name,
weight: data.weight
});
////////////////////////////////////
// Built-in promise-based compose //
////////////////////////////////////
const getPokemons = R.composeP(
R.map(cleanupPokemonData),
Promise.all.bind(Promise),
R.map(fetchPokemon),
R.map(x => x.name),
R.prop("results"),
fetchPokemonList
// getRandomLimit --> this doesn't work because it doesn't return Promise
);
getPokemons(3, 10)
.then(r => console.log("Here are your pokemons:", r))
.catch(err => console.log("Catched an error:", err));
////////////////////
// Custom compose //
////////////////////
const getPokemonsCustom = composeWithPromise(
R.map(cleanupPokemonData),
Promise.all.bind(Promise),
R.map(fetchPokemon),
R.map(x => x.name),
R.prop("results"),
fetchPokemonList,
getRandomLimit
);
getPokemonsCustom(3, 10)
.then(r => console.log("[custom] Here are your pokemons:", r))
.catch(err => console.log("[custom] Catched an error:", err));
@babak-karimi-asl
Copy link

thanks very helpful . how can i handle rejections?

@ehpc
Copy link
Author

ehpc commented Sep 10, 2020

thanks very helpful . how can i handle rejections?

I've updated this gist with real-life example.

@babak-karimi-asl
Copy link

thank you very helpful i needed this

@juanpprieto
Copy link

🔥 thanks for this!

@gbili
Copy link

gbili commented Mar 24, 2023

Great stuff thanks!

I have added some types to your function as well as specific handling for the last call. For the scenario where the return value is an array of promises. In that case, the function does a Promise.all() before returning, which changes the return type from e.g.:

Promise<number>[]

to

Promise<number[]>

It's a choice, but since the same choice is made for intermediate calls, it makes it cleaner.

here's the code

You can also find it in the package npm swiss-army-knifey

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment