The callback inside setTimeout
is going to run in an async manner. Making use of the asynchronousResponse
we can pass our own function as a callback. Notice the statement setTimeout(() => callback(value), delay);
, this callback function will have access to our value and we can make use of that.
The implementation:
Now the idea is to keep storing the values as the functions are called. That way we have the definite order of our calls to getAsyncNumber
. I think this refers to the variable outside the function which holds the returned values. We also keep a field for the status of the items. So we have an array of objects like {status,value}
.
We update our array as our callbacks are called, but never log the resolved values. We only log something based on certain conditions. ONLY WHEN IT IS READY. Any resolved value will only be ready when everything before it is either already logged or in READY
state.
Whenever any callback is called and returns a value, we check whether everything before the item
is done, if yes, then we log the resolved value. If everything before it is in ready state, we log them too and then log our resolved value.
There is an edge case, where some items later in order are ready but they do not get logged. So as a cleanup, we keep track of the number of resolved values too using a counter variable. If all our items have been resolved then we just log everything in the array that is still in READY state.
Here is a working code:
function asynchronousResponse(value, callback) {
var delay = Math.floor(Math.random() * 10) * 1000;
setTimeout(() => callback(value), delay);
}
const vals = [];
let resolved = 0;
function getAsyncNumber(number) {
vals[vals.length] = {status : "NOT_READY", number };
const func = () => {
resolved++;
let ready = 0;
let found = -1;
for (let i = 0 ; i < vals.length;i++) {
if (vals[i].number === number) {
found = i;
if (ready === i) {
vals[i] = {status : "DONE", number : vals[i].number}
for (let j= 0 ; j < i;j++) {
if (vals[j].status === "READY") {
vals[j] = {status : "DONE", number : vals[j].number}
console.log(vals[j].number);
}
}
console.log(number);
} else {
vals[i] = {status : "READY", number : vals[i].number}
}
} else if(found === -1) {
if (vals[i].status === "READY" || vals[i].status === "DONE" ) {
ready++;
}
}
}
if (resolved === vals.length) {
for (let i = 0 ;i < vals.length;i++) {
if (vals[i].status === "READY") {
console.log(vals[i].number);
}
}
}
}
asynchronousResponse(number,func);
}
getAsyncNumber('a');
getAsyncNumber('b');
getAsyncNumber(2);
getAsyncNumber(3);
getAsyncNumber(4);
getAsyncNumber('5');