-
-
Save philipwalton/4dcc5c228e92b01e77bce58e29b22c15 to your computer and use it in GitHub Desktop.
A yielding strategy that ensures tasks will still run before the user leaves.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** A set to keep track of all unresolved yield promises */ | |
const pendingResolvers = new Set(); | |
/** | |
* Resolves all unresolved yield promises and clears the set. | |
*/ | |
function resolvePendingPromises() { | |
for (const resolve of pendingResolvers) { | |
resolve(); | |
} | |
pendingResolvers.clear(); | |
} | |
/** | |
* Returns a promise that, if the document is visible, will resolve in a new | |
* task in the next frame. If the document is not visible (or changes to | |
* hidden prior to the promise resolving), the promise is resolved immediately. | |
* @return {Promise<void>} | |
*/ | |
export function yieldUnlessUrgent() { | |
return new Promise((resolve) => { | |
pendingResolvers.add(resolve); | |
if (document.visibilityState === 'visible') { | |
document.addEventListener('visibilitychange', resolvePendingPromises); | |
// This code uses rAF+setTimeout(0) because these APIs are well-supported, | |
// but you could replace this with any technique you like, | |
// (e.g. scheduler.yield or scheduler.postTask, with fallback). | |
return requestAnimationFrame(() => { | |
setTimeout(() => { | |
pendingResolvers.delete(resolve); | |
resolve(); | |
}, 0); | |
}); | |
} | |
// Still here? Resolve immediately. | |
resolvePendingPromises(); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage for this function would look something like this: