new Promise((resolve, reject) => {})
const getDinosaur = (name) => {
return new Promise((resolve, reject) => {
resolve({name})
})
}
//Shorthand for synchronous values as a promise
const getDinosaur = (name) => Promise.resolve({name})
- Get the asynchronous value
getDinosaur()
.then((dinosaur) => console.log(dinosaur))
getDinosaur()
.then((dinosaur) => dinosaur.name)
.then((name) => console.log(name))
- Name inline functions for readability and debugging
const getName = (dinosaur) => dinosaur.name
const log = (value) => console.log(value)
getDinosaur()
.then(getName)
.then(log)
const getDinosaur = (name) =>
new Promise((resolve) =>
setTimeout(() =>
resolve({name, age: jurrasicPeriod()}),
Math.random() * 3000)
)
const jurrasicPeriod = () => Math.floor(Math.random() * 54e6) + 145e6
const log = (value) => console.log(value)
const dinosaurs = ['Brontosaurus', 'Tyrannosaurus', 'Stegosaurus']
console.time('getDinosaurs')
//Return a promise from your Array.map
Promise.all(dinosaurs.map(getDinosaur))
.then(log)
.then(() => console.timeEnd('getDinosaurs'))
- Get the full stack-trace you expect from a
Promise chain link
- A pass-through that gives access to the current value
//Warning: Modifies the Promise prototype
Promise.prototype.tap = function (onSettled) {
return this.then(
(result) => {
onSettled(result)
return Promise.resolve(result)
},
(reason) => {
onSettled(reason)
return Promise.reject(reason)
}
)
}
const log = (value) => {
if (value instanceof Error) {
console.error(value)
} else {
console.log(value)
}
}
Promise.resolve('Roar!').tap(log)
Promise.reject(new Error('Timed Out')).tap(log)
takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)
- Do something on settled. (fulfilled or rejected)
//Warning: Modifies the Promise prototype
Promise.prototype.always = function (onSettled) {
return this.then(onSettled, onSettled)
}
const log = (value) => {
if (value instanceof Error) {
console.error(value)
return Promise.reject(value)
}
console.log(value)
return Promise.resolve(value)
}
Promise.resolve('Roar!').always(log)
Promise.reject(new Error('Timed Out')).always(log)
takeALongTimeToLoad().always(hideLoadingIndicator)
- 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
- 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)
// This is how JQuery's $.ready() works, but with callbacks
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
- 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
- Return the same
Promise when something is asked for until it resolves
let throttledPromise
const getDinosaurs = () =>
throttledPromise
? throttledPromise
: throttledPromise = Promise.resolve({name}).tap(() => throttledPromise = undefined)
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
- 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
}