Skip to content

Instantly share code, notes, and snippets.

@selfcontained
Created February 15, 2018 00:27
Show Gist options
  • Save selfcontained/5ecd71f3338287994a827ea43ee3daef to your computer and use it in GitHub Desktop.
Save selfcontained/5ecd71f3338287994a827ea43ee3daef to your computer and use it in GitHub Desktop.
Promise Throttler for Async Function
// Example refreshAuth fn that might call Google
function refreshAuth (oldToken, done) {
console.log('actually refreshing the old token', oldToken)
setTimeout(() => {
done(null, getNewToken())
}, 2000)
}
// Pretend we're issuing new tokens
let token = 1
function getNewToken () {
return token++
}
// Pretty generic module to throttle an async function
function promiseThrottler (myAsyncFn) {
let activePromise = null
// return a wrapper to make sure only one person calls refreshAuthFn at a time
return function (...args) {
console.log('promise throttler wrapper')
let done = args.pop()
// No active promise, create one
if (!activePromise) {
console.log('creating promise')
// Setup promise, call refreshAuth fn and resolve or reject based on response
activePromise = new Promise((resolve, reject) => {
// Define a callback for when we actually call myAsyncFn
let myAsyncFnCallback = (err, ...response) => {
// Reject the promise, and pass along the error and response
if (err) {
return reject(err)
}
// Resolve the promise and pass along arguments (not error)
resolve(response)
}
// Kick off refreshAuth call here passing along args and a callback to resolve/reject promise
myAsyncFn.apply(null, args.concat([myAsyncFnCallback]))
})
}
// Wait for promise to resolve, and call done callback
activePromise
.then(resultArgs => {
// call done with a null error and rest of args
done(null, ...resultArgs)
})
.catch(err => {
done(err)
})
// Poor mans Promise.finally()
.then(() => {
activePromise = null
})
}
}
// You could use this in another place like so:
let throttledRefreshAuth = promiseThrottler(refreshAuth)
let myToken = getNewToken()
function gotNewToken (err, newToken) {
if (err) {
return console.error('error refreshing tokne: ', err)
}
myToken = newToken
console.log('new token: ', newToken)
}
throttledRefreshAuth(myToken, gotNewToken)
throttledRefreshAuth(myToken, gotNewToken)
throttledRefreshAuth(myToken, gotNewToken)
// This should get handled in the first round of refreshes
setTimeout(() => {
throttledRefreshAuth(myToken, gotNewToken)
}, 1000)
// Wait awhile and grab more new tokens
setTimeout(() => {
console.log('something comes along later to refresh the token...')
throttledRefreshAuth(myToken, gotNewToken)
throttledRefreshAuth(myToken, gotNewToken)
}, 5000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment