Can we allow JS functions to opt-in to be prempted?
An expensive synchronous function will jank the UI:
function expensive() {}
function responseToInput() {
expensive(); // jank
}
A cooperatively scheduled task can yield to try to not jank the main thread, but it has to yield often enough so that work fits in the frame budget. If a cooperatively scheduled task calls out to an expensive synchronous function, it'll still cause jank.
async function expensive(context) {
for (...) {
await context.yield();
await somethingElse(context);
}
}
function respondToInput() {
await scheduler.schedule(expensive); // jank
}
What if we could allow functions to opt-in to being preempted?
The function would still run on the main thread and have synchronous DOM access, but it could be preempted to respond to user input, animate/layout/paint, etc., based on the UA's scheduling.
function premptable expensive() {
for (...) {
window.foo = 123
div.id = "foo"
…
assert(div.id === "foo")
}
}
function respondToInput() {
await preempt expensive(); // no jank?
}
Preemptible functions and everything they call would have to be compiled with safe points that can yield. Java's green threads added these to the beginning of every block and loop. pthreads have a pthread_suspend function, but it appears to not be widely implemented.
This might not work well at all. Assumptions about state not being mutated by other code without having yielded no longer hold. It might be the case that preemptible functions need to be tied to some isolated DOM to have any hope of being reliable. A preemptible JS realm associated with a closed ShadowRoot might work.
WebKit's Concurrent JavaScript experiment: https://webkit.org/blog/7846/concurrent-javascript-it-can-work/