I have a function which executes an expensive synchronous task. In my case it's a client-side pdf generation through pdfkit, but let's just emulate it with a while-loop sleep.
I'd like to display a "loading" spinner before running the task, and hide it when it's done.
If everything is run synchronously, Angular won't have a chance to run the change detection loop before everything ends, so I thought I just had to find a way to run it asynchronously.
I tried wrapping it in a promise, so let's say I have:
sleep(ms) {
return new Promise((resolve, reject) => {
const expire = (new Date()).getTime() + ms;
while ((new Date()).getTime() < expire);
resolve();
});
}
But whether I run it with a .then() call:
run() {
this.running = true;
this.sleep(2000).then(() => {
this.running = false;
});
}
or with async/await:
async run() {
this.running = true;
await this.sleep(2000);
this.running = false;
}
the change is not detected until the function is over, and nothing gets displayed.
I guess the problem is that Javascript is still single-threaded and the promise is still run immediately when created, so everything basically still runs synchronously.
But even forcing change detection with ChangeDetectorRef.detectChanges() doesn't help.
The only solution I found so far is running it inside a setTimeout hack:
setTimeoutRun() {
this.running = true;
setTimeout(() => {
this.sleep(2000);
this.running = false;
}, 100);
}
but it doesn't look like the right formal solution.
Is setTimeout really the only way?