async function saveSettings () { // A task queue of functions const tasks = [ validateForm, showSpinner, saveToDatabase, updateUI, sendAnalytics ]; let deadline = performance.now() + 50; while (tasks.length > 0) { // Optional chaining operator used here helps to avoid // errors in browsers that don’t support isInputPending
: if (navigator.scheduling?.isInputPending() || performance.now() >= deadline) { // There’s a pending user input, or the // deadline has been reached. Yield here: await yieldToMain(); // Extend the deadline: deadline = performance.now() + 50; } else { // Shift the the task out of the queue: const task = tasks.shift();
}
}
}
// Run the task: task();
isInputPending
is available in navigator.scheduling.isInputPending
, and it returns a boolean if the user has interacted with an element on the page. In this code, you can see how the saveSettings
function adds separate functions to an array of tasks. Then, within a while
loop, this code checks if there is a pending user input. If so, we explicitly yield to the main thread so that interaction can take place. Otherwise, we shift
the next task o the front of the tasks array and run it.
ff
If isInputPending
isn’t supported by the browser, an alternative approach is taken: we set a deadline of 50 milliseconds for each task, and fall back to that approach if necessary. This ensures we’re yielding periodically so that the user experience stays fairly responsive.