mirror-speedometer/resources/shared/step-scheduler.mjs
Camillo Bruni 8344a61b3e
Replace report callback with async await (#566)
We have asyncyfied almost the complete runner by now and no longer need the report callback.
This makes it a bit easer to follow the code path.

Drive-by-fix:
- Remove needless constructor
- Add more tests to cover the schedulers
2026-07-16 11:26:59 +02:00

77 lines
2.2 KiB
JavaScript

class StepScheduler {
constructor(syncCallback, asyncCallback, params) {
this._syncCallback = syncCallback;
this._asyncCallback = asyncCallback;
this._params = params;
}
start() {
return new Promise((resolve) => {
if (this._params.waitBeforeSync)
setTimeout(() => this._scheduleCallbacks(resolve), this._params.waitBeforeSync);
else
this._scheduleCallbacks(resolve);
});
}
}
class RAFStepScheduler extends StepScheduler {
_scheduleCallbacks(resolve) {
requestAnimationFrame(() => this._syncCallback());
requestAnimationFrame(() => {
setTimeout(() => {
this._asyncCallback();
setTimeout(resolve, 0);
}, 0);
});
}
}
class AsyncRAFStepScheduler extends StepScheduler {
static mc = new MessageChannel();
_scheduleCallbacks(resolve) {
let gotTimer = false;
let gotMessage = false;
let gotPromise = false;
const tryTriggerAsyncCallback = () => {
if (!gotTimer || !gotMessage || !gotPromise)
return;
this._asyncCallback();
setTimeout(resolve, 0);
};
requestAnimationFrame(async () => {
await this._syncCallback();
gotPromise = true;
tryTriggerAsyncCallback();
});
requestAnimationFrame(() => {
setTimeout(async () => {
await Promise.resolve();
gotTimer = true;
tryTriggerAsyncCallback();
});
AsyncRAFStepScheduler.mc.port1.addEventListener(
"message",
async function () {
await Promise.resolve();
gotMessage = true;
tryTriggerAsyncCallback();
},
{ once: true }
);
AsyncRAFStepScheduler.mc.port1.start();
AsyncRAFStepScheduler.mc.port2.postMessage("speedometer");
});
}
}
export const STEP_SCHEDULER_LOOKUP = {
__proto__: null,
raf: RAFStepScheduler,
async: AsyncRAFStepScheduler,
};