Last active
April 6, 2024 01:27
-
-
Save jpillora/ded8736def6d72fa684d5603b8b33a1f to your computer and use it in GitHub Desktop.
async javascript test
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
const MAX_INFLIGHT = 4; | |
const TOTAL = 100; | |
// the given dummy api supports a maximum of 4 of inflight requests. | |
// the given code is correct, but it is slow because it processes elements serially. | |
// your task is to process 100 elements as fast as possible. | |
// run this code with "node/bun test.js". | |
// it should print "pass". | |
// no external dependencies are allowed. | |
async function run(elements) { | |
// ============ | |
// your code here starts here | |
const results = []; | |
for (const element of elements) { | |
const result = await api(element); | |
results.push(result); | |
} | |
return results; | |
// your code ends here | |
// ============ | |
} | |
// api accepts 1 element, takes some time, returns a processed element | |
const api = (function () { | |
let inflight = 0; | |
const sleep = (ms) => new Promise((done) => setTimeout(done, ms)); | |
return async (element) => { | |
inflight++; | |
if (inflight > MAX_INFLIGHT) { | |
console.log(`too many requests`); | |
process.exit(1); | |
} | |
const delay = | |
Math.random() < 0.1 ? 1000 : 100 + (Math.random() - 0.5) * 100; | |
await sleep(delay); | |
inflight--; | |
console.log(`processed element ${element}/${TOTAL}`); | |
return "P" + element; | |
}; | |
})(); | |
// check ensures you have processed all elements correctly | |
function check(results) { | |
for (let i = 0; i < TOTAL; i++) { | |
const got = results[i]; | |
const expect = "P" + (i + 1); | |
if (got !== expect) { | |
console.log(`expected result[${i}] to be ${expect}, got ${got}`); | |
process.exit(1); | |
} | |
} | |
console.log("pass"); | |
} | |
// create elements, run user code, check results | |
const elements = new Array(TOTAL).fill(null).map((_, i) => i + 1); | |
run(elements).then(check); |
var total = 100;
var array = [...Array(4)];
async function fn() {
return new Promise((resolve, reject) => setTimeout((Math.random() < .5 ? resolve : reject), Math.floor(Math.random() * 1000)))
.then(() => (--total, ({
completed: 1,
resolved: 1,
rejected: 0,
pending: 0
}))).catch(() => (--total, ({
completed: 1,
rejected: 1,
resolved: 0,
pending: 0
})))
}
while (total) {
await Promise.allSettled(array.map(fn));
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This should keep 4 requests in flight until the end and it doesn't hide exceptions. A promise is created for every call right away but internally
api
is not called unless a spot opens up.Another solution is to use a generator. This implementation allows the generator to control resuming after
yield
. It's a little strange, maybe there's another solution using generators that is more traditional.