Skip to content

Instantly share code, notes, and snippets.

@dannyfritz
Last active August 4, 2021 14:38
Show Gist options
  • Save dannyfritz/bb3f2551a3eb8b3f1dd1 to your computer and use it in GitHub Desktop.
Save dannyfritz/bb3f2551a3eb8b3f1dd1 to your computer and use it in GitHub Desktop.

Revisions

  1. dannyfritz revised this gist Jun 21, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions Promise_Patterns.md
    Original file line number Diff line number Diff line change
    @@ -170,8 +170,8 @@ dinosaurs
    ```js
    const getDinosaur = (name, callback) => callback(null, {name})
    const getDinosaurPromise = (name) => {
    return new Promise(name, (resolve, reject) => {
    getDinosaur((error, data) => {
    return new Promise((resolve, reject) => {
    getDinosaur(name, (error, data) => {
    if (error) {
    return reject(error)
    }
  2. dannyfritz revised this gist May 5, 2016. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions Promise_Patterns.md
    Original file line number Diff line number Diff line change
    @@ -282,6 +282,11 @@ setTimeout(
    * If a connection is unreliable, take data from the cache and update the cache later
    ### WIP Multiple Dependencies
    ### WIP Promise Map
    ### WIP Promise Reduce
    ### WIP Promise Filter
    ### `async`/`await`
    * The future syntax of `Promise`
  3. dannyfritz revised this gist Feb 25, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Promise_Patterns.md
    Original file line number Diff line number Diff line change
    @@ -170,7 +170,7 @@ dinosaurs
    ```js
    const getDinosaur = (name, callback) => callback(null, {name})
    const getDinosaurPromise = (name) => {
    return new Promise((resolve, reject) => {
    return new Promise(name, (resolve, reject) => {
    getDinosaur((error, data) => {
    if (error) {
    return reject(error)
  4. dannyfritz revised this gist Feb 25, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Promise_Patterns.md
    Original file line number Diff line number Diff line change
    @@ -168,7 +168,7 @@ dinosaurs
    * Taking a callback and turning it into a `Promise`
    ```js
    const getDinosaur = (name, callback) => callback({name})
    const getDinosaur = (name, callback) => callback(null, {name})
    const getDinosaurPromise = (name) => {
    return new Promise((resolve, reject) => {
    getDinosaur((error, data) => {
  5. dannyfritz revised this gist Feb 25, 2016. No changes.
  6. dannyfritz revised this gist Feb 25, 2016. 1 changed file with 21 additions and 1 deletion.
    22 changes: 21 additions & 1 deletion Promise_Patterns.md
    Original file line number Diff line number Diff line change
    @@ -25,7 +25,7 @@ getDinosaur("Stegosaurus")
    .then((dinosaur) => console.log(dinosaur))
    ```
    * `.then()` coerces all returned values to a `Promise`
    * `.then()` coerces all returned values to a `Promise` (chaining)
    ```js
    getDinosaur("Brontosaurus")
    @@ -163,6 +163,26 @@ dinosaurs
    .then(renderDinosaursCount)
    ```
    ### Promisify a Callback
    * Taking a callback and turning it into a `Promise`
    ```js
    const getDinosaur = (name, callback) => callback({name})
    const getDinosaurPromise = (name) => {
    return new Promise((resolve, reject) => {
    getDinosaur((error, data) => {
    if (error) {
    return reject(error)
    }
    resolve(data)
    })
    })
    }
    getDinosaurPromise("velociraptor")
    .then(log) // -> {name: "velociraptor"}
    ```
    ### Gate Keeper
    * Wrap DOM Ready event
  7. dannyfritz renamed this gist Feb 25, 2016. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  8. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion details.md
    Original file line number Diff line number Diff line change
    @@ -168,7 +168,7 @@ dinosaurs
    * Wrap DOM Ready event
    ```js
    // This is how JQuery's $.ready() works, but with callbacks
    // This is how JQuery's $.ready() works
    const domReady = () => {
    const readyState = document.readyState
    return readyState === "interactive" || readyState === "complete"
  9. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion details.md
    Original file line number Diff line number Diff line change
    @@ -119,7 +119,7 @@ takeALongTimeToLoad().always(hideLoadingIndicator)
    ## Promise Patterns
    ### Name inline functions
    ### Name Inline Functions
    * Improves readability and debugging
  10. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion details.md
    Original file line number Diff line number Diff line change
    @@ -163,7 +163,7 @@ dinosaurs
    .then(renderDinosaursCount)
    ```
    ### Event Handling
    ### Gate Keeper
    * Wrap DOM Ready event
  11. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 18 additions and 18 deletions.
    36 changes: 18 additions & 18 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -238,26 +238,26 @@ setTimeout(() => {
    * `Promise.race` offers a method to put a time-limit on how long an asynchronous task can take
    ```js
    const retrieveDinosaurs = () =>
    new Promise((resolve) => setTimeout(() => resolve(["Brontosaurus"]), 5000))

    const saveDinosaursToCache = (dinosaurs) =>
    localStorage.dinosaurs = JSON.stringify(dinosaurs)
    const getDinosaursFromCache = () =>
    JSON.parse(localStorage.dinosaurs || '[]')

    const getDinosaurs = () =>
    retrieveDinosaurs().tap(saveDinosaursToCache)
    const getCachedDinosaurs = () =>
    new Promise((resolve, reject) =>
    setTimeout(
    () => resolve(getDinosaursFromCache()),
    1000 //Don't resolve until 5 seconds have passed
    )
    )
    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()])
    .then(log)
    .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
  12. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion details.md
    Original file line number Diff line number Diff line change
    @@ -220,7 +220,7 @@ const resetThrottle = () => throttledPromise = undefined
    const getDinosaurs = () =>
    throttledPromise
    ? throttledPromise
    : throttledPromise = Promise.resolve({name}).tap(resetThrottle, resetThrottle)
    : throttledPromise = Promise.resolve({name}).always(resetThrottle)

    const dinosaurs = getDinosaurs()
    console.log(dinosaurs === getDinosaurs()) //-> true
  13. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -98,7 +98,6 @@ const logError = (reason) => console.error(reason)

    Promise.resolve('Roar!').tap(yell).then(log)
    Promise.reject(new Error('Timed Out')).tap(log, logError)
    takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)
    ```
    ### `.always()`
    @@ -110,7 +109,7 @@ takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)
    Promise.prototype.always = function (onSettled) {
    return this.then(
    (value) => Promise.resolve(onSettled())
    .then(() => Promise.resolve(value)),
    .then(() => value),
    (reason) => onSettled()
    .then(() => Promise.reject(reason)))
    }
  14. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -109,8 +109,10 @@ takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)
    //Warning: Modifies the Promise prototype
    Promise.prototype.always = function (onSettled) {
    return this.then(
    (value) => Promise.resolve(onSettled(value)),
    (reason) => Promise.resolve(onSettled(reason)))
    (value) => Promise.resolve(onSettled())
    .then(() => Promise.resolve(value)),
    (reason) => onSettled()
    .then(() => Promise.reject(reason)))
    }

    takeALongTimeToLoad().always(hideLoadingIndicator)
  15. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 6 additions and 9 deletions.
    15 changes: 6 additions & 9 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -78,12 +78,12 @@ Promise.all(dinosaurs.map(getDinosaur))
    //Warning: Modifies the Promise prototype
    Promise.prototype.tap = function (onFulfilled, onRejected) {
    return this.then(
    (result) => {
    (result) =>
    onFulfilled
    ? Promise.resolve(onFulfilled(result))
    .then(() => result)
    : Promise.resolve(result)
    },
    ,
    (reason) => {
    onRejected
    ? Promise.resolve(onRejected(reason))
    @@ -92,10 +92,11 @@ Promise.prototype.tap = function (onFulfilled, onRejected) {
    }
    )
    }
    const yell = (words) => console.log(`${words.toUpperCase()}!!!`)
    const log = (value) => console.log(value)
    const logError = (reason) => console.error(reason)

    Promise.resolve('Roar!').tap(log)
    Promise.resolve('Roar!').tap(yell).then(log)
    Promise.reject(new Error('Timed Out')).tap(log, logError)
    takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)
    ```
    @@ -108,15 +109,11 @@ takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)
    //Warning: Modifies the Promise prototype
    Promise.prototype.always = function (onSettled) {
    return this.then(
    (value) => Promise.resolve(onSettled(value)),
    (value) => Promise.resolve(onSettled(value)),
    (reason) => Promise.resolve(onSettled(reason)))
    }
    const yell = (words) => console.log(`${words.toUpperCase()}!!!`)
    const log = (value) => console.log(value)

    Promise.resolve('roar').always(log).then(yell)
    Promise.reject(new Error('Timed Out')).always(log)
    takeALongTimeToLoad().catch(renderError).always(hideLoadingIndicator)
    takeALongTimeToLoad().always(hideLoadingIndicator)
    ```
    ## Promise Patterns
  16. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -108,8 +108,8 @@ takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)
    //Warning: Modifies the Promise prototype
    Promise.prototype.always = function (onSettled) {
    return this.then(
    (value) => Promise.resolve(onSettled(value)).then(() => value),
    (reason) => Promise.resolve(onSettled(reason)).then(() => Promise.reject(reason)))
    (value) => Promise.resolve(onSettled(value)),
    (reason) => Promise.resolve(onSettled(reason)))
    }
    const yell = (words) => console.log(`${words.toUpperCase()}!!!`)
    const log = (value) => console.log(value)
  17. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion details.md
    Original file line number Diff line number Diff line change
    @@ -109,7 +109,7 @@ takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)
    Promise.prototype.always = function (onSettled) {
    return this.then(
    (value) => Promise.resolve(onSettled(value)).then(() => value),
    (reason) => Promise.resolve(onSettled(reason)).then(() => value))
    (reason) => Promise.resolve(onSettled(reason)).then(() => Promise.reject(reason)))
    }
    const yell = (words) => console.log(`${words.toUpperCase()}!!!`)
    const log = (value) => console.log(value)
  18. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 29 additions and 0 deletions.
    29 changes: 29 additions & 0 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -235,6 +235,35 @@ setTimeout(() => {
    * 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
    ```js
    const retrieveDinosaurs = () =>
    new Promise((resolve) => setTimeout(() => resolve(["Brontosaurus"]), 5000))

    const saveDinosaursToCache = (dinosaurs) =>
    localStorage.dinosaurs = JSON.stringify(dinosaurs)
    const getDinosaursFromCache = () =>
    JSON.parse(localStorage.dinosaurs || '[]')

    const getDinosaurs = () =>
    retrieveDinosaurs().tap(saveDinosaursToCache)
    const getCachedDinosaurs = () =>
    new Promise((resolve, reject) =>
    setTimeout(
    () => resolve(getDinosaursFromCache()),
    1000 //Don't resolve until 5 seconds have passed
    )
    )
    const log = (value) => console.log(value)
    Promise.race([getDinosaurs(), getCachedDinosaurs()])
    .then(log)
    ```
    * If a connection is unreliable, take data from the cache and update the cache later
    ### `async`/`await`
    * The future syntax of `Promise`
  19. dannyfritz revised this gist Feb 7, 2016. No changes.
  20. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 6 additions and 8 deletions.
    14 changes: 6 additions & 8 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,7 @@ const getDinosaur = (name) => {
    })
    }

    //Shorthand for synchronous values as a promise
    //Shorthand for synchronous values as a Promise
    const getDinosaur = (name) => Promise.resolve({name})
    const getDinosaur = (name) => Promise.reject(new Error("Dinosaurs went extinct!")
    ```
    @@ -21,13 +21,14 @@ const getDinosaur = (name) => Promise.reject(new Error("Dinosaurs went extinct!"
    * Get the asynchronous value
    ```js
    getDinosaur()
    getDinosaur("Stegosaurus")
    .then((dinosaur) => console.log(dinosaur))
    ```
    * Coerces to a `Promise`
    * `.then()` coerces all returned values to a `Promise`
    ```js
    getDinosaur()
    getDinosaur("Brontosaurus")
    .then((dinosaur) => dinosaur.name)
    .then((name) => console.log(name))
    ```
    @@ -57,11 +58,8 @@ 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'))
    .then(log) //-> [{name: "Brontosaurus", age: ...}, {name: "Tyrannosaurus", age: ...}, {name: "Stegosaurus", age: ...}]
    ```
    ## Promise Debugging
  21. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -13,6 +13,7 @@ const getDinosaur = (name) => {

    //Shorthand for synchronous values as a promise
    const getDinosaur = (name) => Promise.resolve({name})
    const getDinosaur = (name) => Promise.reject(new Error("Dinosaurs went extinct!")
    ```
    ### `Promise.then`
  22. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 15 additions and 21 deletions.
    36 changes: 15 additions & 21 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -80,12 +80,16 @@ Promise.all(dinosaurs.map(getDinosaur))
    Promise.prototype.tap = function (onFulfilled, onRejected) {
    return this.then(
    (result) => {
    if (onFulfilled) onFulfilled(result)
    return Promise.resolve(result)
    onFulfilled
    ? Promise.resolve(onFulfilled(result))
    .then(() => result)
    : Promise.resolve(result)
    },
    (reason) => {
    if (onRejected) onRejected(reason)
    return Promise.reject(reason)
    onRejected
    ? Promise.resolve(onRejected(reason))
    .then(() => Promise.reject(reason))
    : Promise.reject(reason)
    }
    )
    }
    @@ -103,27 +107,17 @@ takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)

    ```js
    //Warning: Modifies the Promise prototype
    Promise.prototype.tap = function (onFulfilled, onRejected) {
    Promise.prototype.always = function (onSettled) {
    return this.then(
    (result) => {
    if (onFulfilled) return Promise.resolve(onFulfilled(result)).then(() => result)
    return Promise.resolve(result)
    },
    (reason) => {
    if (onRejected) {
    return Promise.resolve(onRejected(reason))
    .then(() => Promise.reject(reason))
    }
    return Promise.reject(reason)
    }
    )
    (value) => Promise.resolve(onSettled(value)).then(() => value),
    (reason) => Promise.resolve(onSettled(reason)).then(() => value))
    }
    const yell = (words) => console.log(`${words.toUpperCase()}!!!`)
    const log = (value) => console.log(value)
    const logError = (reason) => console.error(reason)

    Promise.resolve('Roar!').tap(log)
    Promise.reject(new Error('Timed Out')).tap(log, logError)
    takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)
    Promise.resolve('roar').always(log).then(yell)
    Promise.reject(new Error('Timed Out')).always(log)
    takeALongTimeToLoad().catch(renderError).always(hideLoadingIndicator)
    ```

    ## Promise Patterns
  23. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 18 additions and 14 deletions.
    32 changes: 18 additions & 14 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -103,23 +103,27 @@ takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)

    ```js
    //Warning: Modifies the Promise prototype
    Promise.prototype.always = function (onSettled) {
    Promise.prototype.tap = function (onFulfilled, onRejected) {
    return this.then(
    (value) => Promise.resolve(onSettled(value)).then(() => value),
    (reason) => Promise.resolve(onSettled(reason)).then(() => value))
    }
    const log = (value) => {
    if (value instanceof Error) {
    console.error(value)
    return Promise.reject(value)
    }
    console.log(value)
    return Promise.resolve(value)
    (result) => {
    if (onFulfilled) return Promise.resolve(onFulfilled(result)).then(() => result)
    return Promise.resolve(result)
    },
    (reason) => {
    if (onRejected) {
    return Promise.resolve(onRejected(reason))
    .then(() => Promise.reject(reason))
    }
    return Promise.reject(reason)
    }
    )
    }
    const log = (value) => console.log(value)
    const logError = (reason) => console.error(reason)

    Promise.resolve('Roar!').always(log)
    Promise.reject(new Error('Timed Out')).always(log)
    takeALongTimeToLoad().always(hideLoadingIndicator)
    Promise.resolve('Roar!').tap(log)
    Promise.reject(new Error('Timed Out')).tap(log, logError)
    takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)
    ```

    ## Promise Patterns
  24. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion details.md
    Original file line number Diff line number Diff line change
    @@ -104,7 +104,9 @@ takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)
    ```js
    //Warning: Modifies the Promise prototype
    Promise.prototype.always = function (onSettled) {
    return this.then(onSettled, onSettled)
    return this.then(
    (value) => Promise.resolve(onSettled(value)).then(() => value),
    (reason) => Promise.resolve(onSettled(reason)).then(() => value))
    }
    const log = (value) => {
    if (value instanceof Error) {
  25. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 12 additions and 9 deletions.
    21 changes: 12 additions & 9 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -30,15 +30,6 @@ getDinosaur()
    .then((dinosaur) => dinosaur.name)
    .then((name) => console.log(name))
    ```
    * Name inline functions for readability and debugging

    ```js
    const getName = (dinosaur) => dinosaur.name
    const log = (value) => console.log(value)
    getDinosaur()
    .then(getName)
    .then(log)
    ```

    ### `Promise.catch`

    @@ -131,6 +122,18 @@ takeALongTimeToLoad().always(hideLoadingIndicator)

    ## Promise Patterns

    ### Name inline functions

    * Improves readability and debugging

    ```js
    const getName = (dinosaur) => dinosaur.name
    const log = (value) => console.log(value)
    getDinosaur()
    .then(getName)
    .then(log)
    ```

    ### Fallback Data

    * Insert a different value if a `Promise` fails.
  26. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 11 additions and 1 deletion.
    12 changes: 11 additions & 1 deletion details.md
    Original file line number Diff line number Diff line change
    @@ -15,7 +15,7 @@ const getDinosaur = (name) => {
    const getDinosaur = (name) => Promise.resolve({name})
    ```

    ### `.then`
    ### `Promise.then`

    * Get the asynchronous value

    @@ -40,6 +40,16 @@ getDinosaur()
    .then(log)
    ```

    ### `Promise.catch`

    * Handle errors with a `Promise`

    ```js
    const getDinosaurs = () => Promise.reject("Connection Timed Out!")
    getDinosaurs()
    .catch((reason) => console.error(reason))
    ```

    ### `Promise.all`

    * Asynchronous iteration
  27. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion details.md
    Original file line number Diff line number Diff line change
    @@ -206,10 +206,11 @@ console.log(getDinosaur('Stegosaurus') === getDinosaur('Stegosaurus')) //-> true

    ```js
    let throttledPromise
    const resetThrottle = () => throttledPromise = undefined
    const getDinosaurs = () =>
    throttledPromise
    ? throttledPromise
    : throttledPromise = Promise.resolve({name}).tap(() => throttledPromise = undefined)
    : throttledPromise = Promise.resolve({name}).tap(resetThrottle, resetThrottle)

    const dinosaurs = getDinosaurs()
    console.log(dinosaurs === getDinosaurs()) //-> true
  28. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 6 additions and 11 deletions.
    17 changes: 6 additions & 11 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -76,28 +76,23 @@ Promise.all(dinosaurs.map(getDinosaur))

    ```js
    //Warning: Modifies the Promise prototype
    Promise.prototype.tap = function (onSettled) {
    Promise.prototype.tap = function (onFulfilled, onRejected) {
    return this.then(
    (result) => {
    onSettled(result)
    if (onFulfilled) onFulfilled(result)
    return Promise.resolve(result)
    },
    (reason) => {
    onSettled(reason)
    if (onRejected) onRejected(reason)
    return Promise.reject(reason)
    }
    )
    }
    const log = (value) => {
    if (value instanceof Error) {
    console.error(value)
    } else {
    console.log(value)
    }
    }
    const log = (value) => console.log(value)
    const logError = (reason) => console.error(reason)

    Promise.resolve('Roar!').tap(log)
    Promise.reject(new Error('Timed Out')).tap(log)
    Promise.reject(new Error('Timed Out')).tap(log, logError)
    takeALongTimeToLoad().tap(log).always(hideLoadingIndicator)
    ```

  29. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 9 additions and 9 deletions.
    18 changes: 9 additions & 9 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -210,17 +210,17 @@ console.log(getDinosaur('Stegosaurus') === getDinosaur('Stegosaurus')) //-> true
    * Return the same `Promise` when something is asked for until it resolves

    ```js
    const cache = {}
    const getDinosaur = (name) =>
    cache[name]
    ? cache[name]
    : cache[name] = Promise.resolve({name}).tap(() => delete cache[name])

    const stegosaurus = getDinosaur('Stegosaurus')
    console.log(stegosaurus === getDinosaur('Stegosaurus')) //-> true
    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(stegosaurus === getDinosaur('Stegosaurus')) //-> false
    console.log(dinosaurs === getDinosaurs()) //-> false
    })
    ```

  30. dannyfritz revised this gist Feb 7, 2016. 1 changed file with 97 additions and 81 deletions.
    178 changes: 97 additions & 81 deletions details.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    ## Promise Patterns
    ## Promises

    ### `new Promise()`

    @@ -40,27 +40,6 @@ getDinosaur()
    .then(log)
    ```

    ### Event Handling

    * Wrap DOM Ready event

    ```js
    // 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)
    ```

    ### `Promise.all`

    * Asynchronous iteration
    @@ -83,6 +62,70 @@ Promise.all(dinosaurs.map(getDinosaur))
    .then(() => console.timeEnd('getDinosaurs'))
    ```

    ## Promise Debugging

    ### Chrome `async` toggle

    * Get the full stack-trace you expect from a `Promise` chain [link](http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/#toc-promises)

    ## Promise Extensions

    ### `.tap()`

    * A pass-through that gives access to the current value

    ```js
    //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)
    ```

    ### `.always()`

    * Do something on settled. (fulfilled or rejected)

    ```js
    //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)
    ```

    ## Promise Patterns

    ### Fallback Data

    * Insert a different value if a `Promise` fails.
    @@ -95,6 +138,9 @@ 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
    @@ -112,6 +158,29 @@ dinosaurs
    .then(renderDinosaursCount)
    ```

    ### Event Handling

    * Wrap DOM Ready event

    ```js
    // 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

    ### Caching

    * Store a `Promise` into a cache instead of the values
    @@ -132,6 +201,10 @@ getDinosaur('Stegosaurus')
    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
    @@ -151,28 +224,8 @@ setTimeout(() => {
    })
    ```

    ### `.always()`

    * Do something on settled. (fulfilled or rejected)

    ```js
    //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)
    ```
    * 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

    ### `async`/`await`

    @@ -186,43 +239,6 @@ async function getDinosaurs () {
    }
    ```

    ## Promise Debugging

    ### `.tap()`

    * A pass-through that gives access to the current value

    ```js
    //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)
    ```

    ### Chrome `async` toggle

    * Get the full stack-trace you expect from a `Promise` chain [link](http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/#toc-promises)

    ## References

    * [Kornel Lesiński: And .then() what? Promise programming patterns – Falsy Values 2015](https://www.youtube.com/watch?v=0ih21-gX2Rg)