yieldtomain
v1.0.3
Published
A utility function to yield to the main thread in JavaScript
Maintainers
Readme
yieldToMain
A utility function to yield execution to the main thread in JavaScript, preventing UI blocking. Uses scheduler.yield() when available, falling back to setTimeout.
The gist is this:
function yieldToMain() {
const scheduler = globalThis.scheduler;
if (scheduler && typeof scheduler.yield === 'function') {
return scheduler.yield();
}
return new Promise((resolve) => {
setTimeout(resolve, 0);
});
}Feel free to copy and paste this into your codebase. Or continue with using it as a module etc., as described below.
Installation
npm install yieldtomainUsage
The library can be used in a bunch o' JavaScript environments:
ES Modules
import yieldToMain from 'yieldtomain';
async function processItems(items) {
for (const item of items) {
await yieldToMain();
// Process item
}
}CommonJS
const yieldToMain = require('yieldtomain');
async function heavyTask() {
for (let i = 0; i < 1000000; i++) {
if (i % 1000 === 0) await yieldToMain();
// Compute something
}
}Browser
<script src="dist/yieldToMain.browser.js"></script>
<script>
async function nonBlockingTask() {
for (let i = 0; i < 1000000; i++) {
if (i % 1000 === 0) await yieldToMain();
// Heavy computation
}
}
</script>Demo
Check out the examples/heavy.html demo to see the difference between blocking and non-blocking computations. The demo includes:
- A counter animation to visualize thread blocking
- Pure computation examples (where "pure" means a JS loop without any DOM involvement)
- DOM access in addition to computations
- Multiple runs while reporting the median
A live version of the demo is right here.
Build Formats
The library is distributed in multiple formats:
dist/yieldToMain.esm.js- ECMAScript Moduledist/yieldToMain.cjs.js- CommonJSdist/yieldToMain.browser.js- Minified browser build with an IIFE that provides a globalyieldToMain()function
All builds include source maps and TypeScript type definitions.
API
function yieldToMain(): Promise<void>;The function returns a Promise that resolves after yielding execution to the main thread. It uses:
scheduler.yield()if availablesetTimeout(0)fallback
Development
# Install dependencies
npm install
# Build all formats and types
npm run build
# Run tests
npm test
# Run tests in watch mode
npm run test:watchLicense
MIT
Further Reading
The yieldToMain() function is in no way my invention, I was just surprised it's not widely available in npm, so I decided to create a package for it. It's like a folk song that everyone knows, and yet it's origins are a little mirky. For more nitty-gritty details here's a selection of light (haha!) reading:
- Breaking Up Long Tasks (2022) - Introduction to long tasks, INP metric, and various yielding strategies including isInputPending and postTask.
- Yielding to the Main Thread: How Breaking Up Tasks Can Fix INP (2023) - A deep dive into how yielding improves Interaction to Next Paint (INP) scores and overall responsiveness.
- Breaking Up with Long Tasks: How I Learned to Group Loops and Wield the Yield (2024) - Advanced techniques for batching and optimizing yield calls, including frame rate considerations and background tab handling.
- setTimeout vs rAF when yielding (2024)
