[Ramda] Refactor a Promise Chain to Function Composition using Ramda
Promise chains can be a powerful way to handle a series of transformations to the results of an async call. In some cases, additional promises are required along the way. In cases where there are no new promises, function composition can reduce the number of dot chained then
s you need. In this lesson, we'll look at how to take a promise chain, and reduce it down with function composition.
const deckUrl = 'https://deckofcardsapi.com/api/deck/new/shuffle/?cards=AS,2S,5C,3C,KD,AH,QH,2C,KS,8C'; fetch(deckUrl) .then(res => res.json()) .then(deck => fetch(`https://deckofcardsapi.com/api/deck/${deck.deck_id}/draw/?count=10`) .then(res => res.json()) .then(deck => deck.cards) .then(cards => cards.filter(c => c.suit === 'CLUBS')) .then(cards => cards.map(c => c.image)) .then(cards => cards.sort((c1, c2) => c1.value - c2.value))) .then(cards => cards.map(u => `<img width="100" src="${u}"/>`).join('')) .then(imgString => { document.querySelector('#cards').innerHTML = `<div>${imgString}</div>` })
We want to use Ramda to improve code:
Using R.prop and R.map:
// from .then(deck => deck.cards) // to .then(prop('cards')) // from .then(cards => cards.map(c => c.image)) //to .then(map(prop('image')))
Using R.propEq and R.filter:
// from .then(cards => cards.filter(c => c.suit === 'CLUBS')) //to .then(filter(propEq('suit', 'CLUBS')))
Using R.sortBy:
// from .then(cards => cards.sort((c1, c2) => c1.value - c2.value))) // to .then(sortBy(prop('value'))))
Using R.compose:
// from .then(cards => cards.map(u => `<img width="100" src="${u}"/>`).join('')) // to .then(compose(join(''), map(u => `<img width="100" src="${u}"/>`)))
Now it looks like:
const {prop, filter, map, sortBy, propEq, join, compose, pluck} = R const deckUrl = 'https://deckofcardsapi.com/api/deck/new/shuffle/?cards=AS,2S,5C,3C,KD,AH,QH,2C,KS,8C' fetch(deckUrl) .then(res => res.json()) .then(deck => fetch(`https://deckofcardsapi.com/api/deck/${deck.deck_id}/draw/?count=10`) .then(res => res.json()) .then(prop('cards')) .then(filter(propEq('suit', 'CLUBS'))) .then(map(prop('image'))) .then(sortBy(prop('value'))) .then(compose(join(''), map(u => `<img width="100" src="${u}"/>`))) .then(imgString => { document.querySelector('#cards').innerHTML = `<div>${imgString}</div>` })
We can also pull out each step as a function.
const {prop, filter, map, sortBy, propEq, join, compose, pluck} = R const deckUrl = 'https://deckofcardsapi.com/api/deck/new/shuffle/?cards=AS,2S,5C,3C,KD,AH,QH,2C,KS,8C' const getId = prop('deck_id'); const drawCards = id => fetch(`https://deckofcardsapi.com/api/deck/${id}/draw/?count=10`) .then(res => res.json()); const getCards = prop('cards'); const justClubs = filter(propEq('suit', 'CLUBS')); const sortByValue = sortBy(prop('value')); const getImages = map(prop('image')); const toImgString = compose(join(''), map(u => `<img width="100" src="${u}"/>`)); const render = imgString => { document.querySelector('#cards').innerHTML = `<div>${imgString}</div>` }; fetch(deckUrl) .then(res => res.json()) .then(getId) .then(drawCards) .then(getCards) .then(justClubs) .then(getImages) .then(sortByValue) .then(toImgString) .then(render);
Using R.pluck to replace R.map(R.prop(''));
const getImages = pluck('image');
const {prop, filter, map, sortBy, propEq, join, compose, pluck} = R const deckUrl = 'https://deckofcardsapi.com/api/deck/new/shuffle/?cards=AS,2S,5C,3C,KD,AH,QH,2C,KS,8C' const getId = prop('deck_id'); const drawCards = id => fetch(`https://deckofcardsapi.com/api/deck/${id}/draw/?count=10`) .then(res => res.json()); const getCards = prop('cards'); const justClubs = filter(propEq('suit', 'CLUBS')); const sortByValue = sortBy(prop('value')); const getImages = pluck('image'); const toImgString = compose(join(''), map(u => `<img width="100" src="${u}"/>`)); const render = imgString => { document.querySelector('#cards').innerHTML = `<div>${imgString}</div>` }; const transformData = compose(toImgString, getImages, sortByValue, justClubs, getCards) fetch(deckUrl) .then(res => res.json()) .then(getId) .then(drawCards) .then(compose(render, transformData));