SPLIT INTO MULTIPLE PAGES

Promise Patterns for Happier Relationships

:construction: Multiple Dependencies

Fallback Data

  • Insert a different value if a Promise fails.
const getData = () => Promise.reject(new Error('Connection Timed Out'))
const getCachedData = () => Promise.resolve({name: 'Brontosaurus'})
const log = (value) => console.log(value)
getData()
  .catch(getCachedData) //Could get data from localStorage
  .then(log)
  • Can be used any time an external resource isn't reliable

Fanning

  • Taking a Promise and independently calling multiple .then() on it
const dinosaurs = getDinosaurs() //Returns a promise

dinosaurs
  .then(cacheDinosaurs)

dinosaurs
  .then(renderDinosaurList)

dinosaurs
  .then(renderDinosaursCount)

Promisify a Callback

  • Taking a callback and turning it into a Promise
const getDinosaur = (name, callback) => callback(null, {name})
const getDinosaurPromise = (name) => {
  return new Promise((resolve, reject) => {
    getDinosaur(name, (error, data) => {
      if (error) {
        return reject(error)
      }
      resolve(data)
    })
  })
}
getDinosaurPromise("velociraptor")
  .then(log) // -> {name: "velociraptor"}

Gate Keeper

  • Wrap DOM Ready event
// This is how JQuery's $.ready() works
const domReady = () => {
  const readyState = document.readyState
  return readyState === "interactive" || readyState === "complete"
    ? Promise.resolve()
    : new Promise((resolve) =>
      document.addEventListener("DOMContentLoaded", resolve))
}
const roar = () => console.log("Roar!!!")
const attachRoarHandler = () => 
  document.querySelector("button").addEventListener("click", roar);

domReady() // Promise only resolves when the DOM is loaded
  .then(attachRoarHandler)
  • Can be coupled with fanning to great effect

Caching

  • Store a Promise into a cache instead of the values
const cache = {}
const getDinosaur = (name) => 
  cache[name]
    ? cache[name]
    : cache[name] = Promise.resolve({name})
const log = (value) => console.log(value)

getDinosaur('Stegosaurus')
  .then(log)
getDinosaur('Stegosaurus')
  .then(log)

console.log(getDinosaur('Stegosaurus') === getDinosaur('Stegosaurus')) //-> true
  • This way, a hundred different things can request a remote resource and it will only hit it once
    • It does this by storing an unfulfilled Promise
  • Synchronous values don't populate the cache until the request finished causing all of the requests that come in before the request resolves will also try and hit the external resource

Throttling

  • Return the same Promise when something is asked for until it resolves
let throttledPromise
const resetThrottle = () => throttledPromise = undefined
const getDinosaurs = () => 
  throttledPromise
    ? throttledPromise
    : throttledPromise = Promise.resolve({name}).always(resetThrottle)

const dinosaurs = getDinosaurs()
console.log(dinosaurs === getDinosaurs()) //-> true
setTimeout(() => {
  //By now, the Promise has settled and is no longer pending
  console.log(dinosaurs === getDinosaurs()) //-> false
})
  • This keeps data fresh, but prevents parallel requests for the same thing
  • All parallel requests get the same Promise back until it resolves and a new Promise is made

Fastest Promise

  • Promise.race offers a method to put a time-limit on how long an asynchronous task can take
let cache = '[]'

const retrieveDinosaurs = () => //Don't resolve until 5 seconds have passed
  new Promise((resolve) => setTimeout(() => resolve(["Brontosaurus"]), 2000))
const getCachedDinosaurs = () => //Don't resolve until 2 seconds have passed
  new Promise((resolve) => setTimeout(() => resolve(getDinosaursFromCache()), 1000))

const saveDinosaursToCache = (dinosaurs) => cache = JSON.stringify(dinosaurs)
const getDinosaursFromCache = () => JSON.parse(cache)

const getDinosaurs = () => retrieveDinosaurs().tap(saveDinosaursToCache)
const log = (value) => console.log(value)

Promise.race([getDinosaurs(), getCachedDinosaurs()])
  .tap(log)

setTimeout(
  () => Promise.race([getDinosaurs(), getCachedDinosaurs()])
    .tap(log),
  3000)
  • If a connection is unreliable, take data from the cache and update the cache later

async/await

  • The future syntax of Promise
async function getDinosaurs () {
  const dinosaurs = await api.dinosaurs.get() //returns a Promise
  const names = dinosaurs.map((dinosaur) => dinosaur.name)
  return names
}

results matching ""

    No results matching ""