Skip to main content

scheduleMicrotask

Schedules a function to execute in the microtask queue with optimal cross-platform performance. Enqueues a callback function to execute immediately after the current execution stack completes but before any macrotasks (setTimeout, I/O, rendering) are processed. Uses the most efficient microtask scheduling mechanism available in the current environment. Provides the highest execution priority in the JavaScript event loop.

Signature

const scheduleMicrotask: Fn<[task: Fn<[], void>], void>

Parameters

NameTypeDescription
task-Function to execute in the microtask queue

Examples

Basic microtask scheduling

import { scheduleMicrotask } from '@winglet/common-utils';

console.log('1: Synchronous code');

// Schedule microtask (executes before macrotasks)
scheduleMicrotask(() => {
console.log('3: Microtask executed');
});

// Schedule macrotask for comparison
setTimeout(() => {
console.log('4: Macrotask executed');
}, 0);

console.log('2: More synchronous code');

// Output order:
// 1: Synchronous code
// 2: More synchronous code
// 3: Microtask executed
// 4: Macrotask executed

Event loop execution order demonstration

const executionOrder: string[] = [];

// Synchronous execution
executionOrder.push('sync-1');

// Multiple microtasks
scheduleMicrotask(() => {
executionOrder.push('microtask-1');

// Nested microtask (executes in same phase)
scheduleMicrotask(() => {
executionOrder.push('nested-microtask');
});
});

scheduleMicrotask(() => {
executionOrder.push('microtask-2');
});

// Macrotask (executes after all microtasks)
setTimeout(() => {
executionOrder.push('macrotask');
}, 0);

executionOrder.push('sync-2');

// Final order: ['sync-1', 'sync-2', 'microtask-1', 'microtask-2', 'nested-microtask', 'macrotask']

State synchronization and cleanup

// Ensure state updates are processed before UI updates
class StateManager {
private state: any = {};
private updateCallbacks: (() => void)[] = [];
private updateScheduled = false;

setState(newState: any) {
Object.assign(this.state, newState);

if (!this.updateScheduled) {
this.updateScheduled = true;

// Schedule state synchronization in microtask
scheduleMicrotask(() => {
this.updateScheduled = false;
this.updateCallbacks.forEach(callback => callback());
});
}
}

onUpdate(callback: () => void) {
this.updateCallbacks.push(callback);
}
}

// DOM synchronization
function scheduleImmediateUpdate(element: HTMLElement, value: string) {
scheduleMicrotask(() => {
element.textContent = value;
});
}

Async operation coordination

// Coordinate multiple async operations
async function coordinatedAsync() {
console.log('Starting coordination');

// Immediate microtask execution
await new Promise<void>(resolve => {
scheduleMicrotask(() => {
console.log('Microtask 1 executed');
resolve();
});
});

// Chain another microtask
await new Promise<void>(resolve => {
scheduleMicrotask(() => {
console.log('Microtask 2 executed');
resolve();
});
});

console.log('Coordination complete');
}

// Error handling in microtasks
function safeMicrotask(task: () => void, errorHandler?: (error: Error) => void) {
scheduleMicrotask(() => {
try {
task();
} catch (error) {
if (errorHandler) {
errorHandler(error as Error);
} else {
console.error('Microtask error:', error);
}
}
});
}

React/Vue integration patterns

// Flush state updates before rendering
function flushStateUpdates(callback: () => void) {
scheduleMicrotask(() => {
callback();

// Ensure DOM updates complete before next operation
scheduleMicrotask(() => {
console.log('State and DOM synchronized');
});
});
}

// Testing utilities
function flushMicrotasks(): Promise<void> {
return new Promise(resolve => {
scheduleMicrotask(resolve);
});
}

// Usage in tests
async function testAsyncBehavior() {
// Trigger async operation
triggerAsyncUpdate();

// Wait for microtasks to complete
await flushMicrotasks();

// Assert final state
expect(finalState).toBe(expectedValue);
}

Performance optimization patterns

// Batch multiple synchronous operations
class BatchProcessor {
private pendingItems: any[] = [];
private processingScheduled = false;

addItem(item: any) {
this.pendingItems.push(item);

if (!this.processingScheduled) {
this.processingScheduled = true;

scheduleMicrotask(() => {
this.processBatch();
this.processingScheduled = false;
});
}
}

private processBatch() {
const items = [...this.pendingItems];
this.pendingItems.length = 0;

// Process all items in single operation
this.processItems(items);
}

private processItems(items: any[]) {
// Batch processing logic
}
}

// Debounce with immediate execution
function createMicrotaskDebouncer<T extends (...args: any[]) => void>(
fn: T,
immediate = false
): T {
let scheduled = false;
let args: Parameters<T>;

return ((...newArgs: Parameters<T>) => {
args = newArgs;

if (immediate && !scheduled) {
fn(...args);
}

if (!scheduled) {
scheduled = true;

scheduleMicrotask(() => {
scheduled = false;
if (!immediate) {
fn(...args);
}
});
}
}) as T;
}

Custom scheduling systems

// Priority-based microtask scheduler
class PriorityMicrotaskScheduler {
private highPriorityQueue: (() => void)[] = [];
private normalPriorityQueue: (() => void)[] = [];
private lowPriorityQueue: (() => void)[] = [];
private processing = false;

scheduleHigh(task: () => void) {
this.highPriorityQueue.push(task);
this.scheduleProcessing();
}

scheduleNormal(task: () => void) {
this.normalPriorityQueue.push(task);
this.scheduleProcessing();
}

scheduleLow(task: () => void) {
this.lowPriorityQueue.push(task);
this.scheduleProcessing();
}

private scheduleProcessing() {
if (!this.processing) {
this.processing = true;

scheduleMicrotask(() => {
this.processQueues();
this.processing = false;
});
}
}

private processQueues() {
// Process high priority first
while (this.highPriorityQueue.length > 0) {
const task = this.highPriorityQueue.shift()!;
task();
}

// Then normal priority
while (this.normalPriorityQueue.length > 0) {
const task = this.normalPriorityQueue.shift()!;
task();
}

// Finally low priority
while (this.lowPriorityQueue.length > 0) {
const task = this.lowPriorityQueue.shift()!;
task();
}
}
}

Playground

import { scheduleMicrotask } from '@winglet/common-utils';

console.log('1: Synchronous code');

// Schedule microtask (executes before macrotasks)
scheduleMicrotask(() => {
console.log('3: Microtask executed');
});

// Schedule macrotask for comparison
setTimeout(() => {
console.log('4: Macrotask executed');
}, 0);

console.log('2: More synchronous code');

// Output order:
// 1: Synchronous code
// 2: More synchronous code
// 3: Microtask executed
// 4: Macrotask executed

Notes

Event Loop Integration:

  • Execution Timing: Runs immediately after current execution stack
  • Priority: Highest priority, before all macrotasks and I/O
  • Queue Processing: All microtasks execute before next event loop phase
  • Nested Behavior: New microtasks during execution are processed immediately

Platform Behavior:

  • Modern Browsers: Uses native queueMicrotask for optimal performance
  • Node.js: Native queueMicrotask support with consistent timing
  • Legacy Environments: Promise-based fallback with identical behavior
  • Web Workers: Consistent behavior across all worker contexts

Performance Characteristics:

  • Time Complexity: O(1) for scheduling operation
  • Space Complexity: O(1) per scheduled task
  • Scheduling Overhead: ~0.0001ms with native implementation
  • Memory Usage: Minimal, automatic cleanup after execution

Comparison with Alternatives:

  • Promise.resolve().then(): Similar timing, slightly more overhead
  • setTimeout(0): Much slower, executes in macrotask queue
  • requestAnimationFrame: Tied to rendering, different timing
  • process.nextTick (Node.js): Similar but different queue priority

Use Cases:

  • State synchronization before rendering
  • Batch processing of synchronous operations
  • Error handling and cleanup operations
  • Testing utilities for async code
  • React/Vue integration for immediate updates
  • Custom scheduling and priority systems
  • DOM manipulation coordination
  • Performance optimization through batching

Best Practices:

  • Use for operations that must complete before macrotasks
  • Batch multiple operations in single microtask when possible
  • Handle errors appropriately within microtask callbacks
  • Avoid infinite microtask loops that block the event loop
  • Use for state synchronization in reactive systems
  • Prefer for immediate DOM updates over setTimeout

Event Loop Timing:

  • Phase 1: Execute all synchronous code
  • Phase 2: Execute all microtasks (including nested ones)
  • Phase 3: Execute macrotasks (setTimeout, I/O, etc.)
  • Phase 4: Browser rendering (if applicable)
  • Repeat: Next event loop iteration

Browser/Runtime Compatibility:

  • Modern Browsers: Native queueMicrotask support (Chrome 71+, Firefox 69+, Safari 13.1+)
  • Node.js: Native support in v11.0.0+
  • Legacy Support: Promise-based fallback for universal compatibility
  • TypeScript: Full type safety with proper function signatures