I'm running into an issue where a callback sent to setTimeout
from a resolved promise never get executed.
supposed I have the following:
class Foo {
constructor(foo) {
this.foo = foo;
}
async execUntilStop(callback) {
const timeoutLoopCallback = () => {
if (this.stopExec) return;
callback({ data: 'data' });
setTimeout(timeoutLoopCallback, 10);
};
setTimeout(timeoutLoopCallback, 10);
return { data: 'data'};
}
stop() {
this.stopExec = true;
}
}
const myFunc = async function () {
let callbackCalled = false;
const callback = () => callbackCalled = true;
foo = new Foo('foo');
foo.execUntilStop(callback);
const hasCallbackCalled = async () => callbackCalled;
while(!(await hasCallbackCalled())) null;
foo.stop();
return 'success!';
};
myFunc().then((result) => console.log(result))
myFunc()
never resolves as it is continually waiting for callbackCalled
to be true
.
What am I missing here? I believe the event loop shouldn't be blocked since I'm calling await on an async function to check if the callback has been called. I hypothesise it has something to do with timeoutLoopCallback
being bound to a resolved promise but I'm not a javascript expert and could use some feedback.
Note: This looks a little odd but essentially this is derivative of a class I'm trying to write test cases for that will be continually executing a callback until stopped.
SOLVED
Using what I learned from @traktor53 answer, I wrote a handy dandy wait
function:
// resolves when callback returns true
const wait = callback => new Promise((resolve, reject) => {
const end = () => {
try {
if (callback()) {
resolve(true);
} else {
setTimeout(end, 0);
}
} catch(error) {
reject(error);
}
};
setTimeout(end, 0);
});
class Foo {
constructor(foo) {
this.foo = foo;
}
async execUntilStop(callback) {
const timeoutLoopCallback = () => {
if (this.stopExec) return;
callback({ data: 'data' });
setTimeout(timeoutLoopCallback, 10);
};
setTimeout(timeoutLoopCallback, 10);
return { data: 'data'};
}
stop() {
this.stopExec = true;
}
}
const myFunc = async function (num) {
let callbackCalled = false;
const callback = () => callbackCalled = true;
foo = new Foo('foo');
foo.execUntilStop(callback);
const hasCallbackCalled = () => callbackCalled;
await wait(hasCallbackCalled);
foo.stop();
return 'success!';
};
myFunc().then((result) => console.log(result)); // => success!
yeah this is node. I'll add a tag.actually I'll just change it to setTimeout – rudolph9 Apr 26 '18 at 01:27