requestAnimationFrame always called first
tested on:
- chrome 80
- firefox 70
- safari 13
requestAnimationFrame sometimes called first
tested on:
- chrome 80
function slowOp(factor) { | |
const n = 999999 * factor; | |
let i = -1; | |
while (++i < n) { | |
Math.pow(23, i % 3); | |
} | |
} | |
function runTimers({timeoutInterval, shouldNest}) { | |
return new Promise(resolve => { | |
let timeoutCalled | |
let requestAnimationFrameCalled; | |
setTimeout(onTimeout, timeoutInterval); | |
if (shouldNest) { | |
requestAnimationFrame(() => requestAnimationFrame(onAnimationFrame)); | |
} else { | |
requestAnimationFrame(onAnimationFrame); | |
} | |
function onAnimationFrame() { | |
if (timeoutCalled) { | |
console.log('requestAnimationFrame called **after** timeout'); | |
} else { | |
console.log('requestAnimationFrame called **before** timeout'); | |
} | |
requestAnimationFrameCalled = true; | |
maybeResolve(); | |
} | |
function onTimeout() { | |
timeoutCalled = true | |
maybeResolve(); | |
} | |
function maybeResolve() { | |
if (timeoutCalled && requestAnimationFrameCalled) { | |
resolve(); | |
} | |
} | |
}); | |
} | |
async function runOnce(opts) { | |
const { slowdownFactor } = opts; | |
let done | |
runTimers(opts).then(() => done = true); | |
while (!done) { | |
await new Promise(resolve => setTimeout(resolve, 0)); | |
slowOp(slowdownFactor); | |
} | |
} | |
async function run(opts) { | |
let i = -1; | |
while (++i < opts.n) await runOnce(opts); | |
} | |
run({ | |
n: 10, | |
timeoutInterval: 20, | |
slowdownFactor: 1000, | |
shouldNest: false | |
}); |