Created
June 4, 2019 13:09
-
-
Save lovasoa/03f15535f054b0d0166e3df5f8e016e0 to your computer and use it in GitHub Desktop.
Balance load between asynchronous functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Balances work between several asynchronous functions. | |
* Given an array of async functions that make the same computation, | |
* returns a single function that has the computation made by | |
* the first idle function. | |
* | |
* @template T,U | |
* @param {((...args:T) => Promise<U>)[]} functions | |
* @param {boolean?} fifo Whether to process the arguments in fifo or lifo | |
* @returns {(...args:T) => Promise<U>} | |
* | |
* @example | |
* let f = n => (path) => fetch(`//server${n}.com/${path}`) | |
* let balanced = balance([f(1), f(2)]); | |
* balanced("x") // fetches server2.com/x | |
* balanced("y") // fetches server1.com/y | |
* balanced("z") // fetches server1.com/z, or server2.com/z, | |
* // depending on which one of the previous request terminated first | |
*/ | |
function balance(functions, fifo = true) { | |
let idle = [...functions]; | |
let queue = []; | |
async function consume() { | |
let f = idle.pop(); | |
if (f === undefined) return; // No idle function | |
let obj = queue.pop(); | |
if (obj === undefined) { | |
idle.push(f); | |
} else { | |
let { accept, reject, args } = obj; | |
await f(...args).then(accept).catch(reject); | |
idle.push(f); | |
consume(); | |
} | |
} | |
return function balanced(...args) { | |
return new Promise((accept, reject) => { | |
let obj = { accept, reject, args }; | |
if (fifo) queue.unshift(obj); | |
else queue.push(obj); | |
consume(); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment