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 => ``).join('')) .then(imgString => { document.querySelector('#cards').innerHTML = `${imgString}` })
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 => ``).join(''))// to.then(compose(join(''), map(u => ``)))
Now it looks like:
const {prop, filter, map, sortBy, propEq, join, compose, pluck} = Rconst 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 => ``))) .then(imgString => { document.querySelector('#cards').innerHTML = `${imgString}` })
We can also pull out each step as a function.
const {prop, filter, map, sortBy, propEq, join, compose, pluck} = Rconst 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 => ``));const render = imgString => { document.querySelector('#cards').innerHTML = `${imgString}` }; 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} = Rconst 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 => ``));const render = imgString => { document.querySelector('#cards').innerHTML = `${imgString}` }; const transformData = compose(toImgString, getImages, sortByValue, justClubs, getCards) fetch(deckUrl) .then(res => res.json()) .then(getId) .then(drawCards) .then(compose(render, transformData));