阿里云主机折上折
  • 微信号
Current Site:Index > Optimization of microtasks and macrotasks

Optimization of microtasks and macrotasks

Author:Chuan Chen 阅读数:58518人阅读 分类: 性能优化

Microtasks and Macrotasks Optimization

Microtasks and macrotasks are core concepts in JavaScript's event loop, crucial for performance optimization. Understanding their execution order and differences can effectively prevent code blocking and improve rendering efficiency, especially in complex interaction scenarios.

Event Loop Basics

JavaScript adopts a single-threaded model, handling asynchronous operations through the event loop mechanism. When the call stack is empty, the event loop retrieves tasks from the task queue for execution. Tasks are divided into two categories:

  1. Macrotasks: Includes entire script code, setTimeout, setInterval, I/O operations, UI rendering, etc.
  2. Microtasks: Includes Promise.then, MutationObserver, process.nextTick (Node.js)

Execution order follows:

// Typical execution order example
console.log('script start'); // Macrotask

setTimeout(() => {
  console.log('setTimeout'); // Macrotask
}, 0);

Promise.resolve().then(() => {
  console.log('promise1'); // Microtask
}).then(() => {
  console.log('promise2'); // Microtask
});

console.log('script end'); // Macrotask

/*
Output order:
script start
script end
promise1
promise2
setTimeout
*/

Microtask Characteristics and Optimization

Microtasks execute immediately after the current macrotask ends, having higher priority. This feature can be used for:

Batch DOM Updates

// Inefficient approach
elements.forEach(el => {
  el.style.width = '100px'; // Triggers multiple reflows
});

// Optimized solution
Promise.resolve().then(() => {
  elements.forEach(el => {
    el.style.width = '100px'; // Single reflow
  });
});

State Synchronization

let data;
fetchData().then(res => {
  data = res; // Assignment in microtask
});

// Subsequent code can be wrapped in a microtask to ensure data availability
Promise.resolve().then(() => {
  processData(data);
});

Macrotask Optimization Strategies

Macrotasks are suitable for non-urgent time-consuming operations. Proper scheduling can prevent UI freezing:

Long Task Decomposition

// Original long task
function processHugeArray() {
  for(let i=0; i<1e6; i++) {
    // Time-consuming calculations...
  }
}

// Decomposed into macrotasks
function chunkedProcess(array, index = 0, chunkSize = 1000) {
  const end = Math.min(index + chunkSize, array.length);
  for(; index < end; index++) {
    // Process current chunk
  }
  if(index < array.length) {
    setTimeout(() => chunkedProcess(array, index, chunkSize));
  }
}

Animation Optimization

// Use requestAnimationFrame instead of setTimeout
function animate() {
  // Animation logic...
  requestAnimationFrame(animate);
}
animate();

Mixed Usage Scenarios

Complex interactions require coordination of both task types:

User Input Handling

input.addEventListener('input', () => {
  // Immediate feedback (microtask)
  Promise.resolve().then(updatePreview);
  
  // Time-consuming operations (macrotask)
  setTimeout(() => {
    sendAnalytics();
    updateDatabase();
  }, 0);
});

Server-Side Data Stream Processing

function processStream(stream) {
  stream.on('data', chunk => {
    // Microtask for core data processing
    Promise.resolve().then(() => parseChunk(chunk));
    
    // Macrotask for non-critical operations
    setTimeout(() => logChunk(chunk), 0);
  });
}

Performance Pitfalls and Avoidance

Microtask Accumulation

// Dangerous recursive microtask
function recursiveMicrotask() {
  Promise.resolve().then(recursiveMicrotask); // Causes main thread blockage
}

Macrotask Delay Accumulation

// Timer drift issue
let start = Date.now();
let count = 0;

function delayedTask() {
  count++;
  const offset = Date.now() - start;
  console.log(`Execution ${count}, deviation: ${offset - count*100}ms`);
  
  if(count < 10) {
    setTimeout(delayedTask, 100);
  }
}
setTimeout(delayedTask, 100);

Modern API Optimization Applications

queueMicrotask API

// More direct microtask API than Promise.resolve()
function criticalUpdate() {
  queueMicrotask(() => {
    updateUI();
    logState();
  });
}

requestIdleCallback

// Execute tasks during idle periods
requestIdleCallback((deadline) => {
  while(deadline.timeRemaining() > 0) {
    performBackgroundWork();
  }
});

Framework Practices

React Batch Updates

// React uses microtasks for state batch updates
function Component() {
  const [state, setState] = useState();
  
  const handleClick = () => {
    setState(1);  // Doesn't immediately re-render
    setState(2);  // Merged update
  };
}

Vue nextTick

// Vue's nextTick implementation
this.message = 'updated';
this.$nextTick(() => {
  // Executes after DOM updates
  console.log(this.$el.textContent);
});

Debugging and Monitoring

Chrome Performance Panel

  1. Identify long tasks (exceeding 50ms)
  2. Analyze task composition (macrotask/microtask ratio)
  3. Detect task scheduling frequency

PerformanceObserver

const observer = new PerformanceObserver((list) => {
  for(const entry of list.getEntries()) {
    console.log('[Long Task]', entry);
  }
});
observer.observe({entryTypes: ['longtask']});

Node.js Environment Differences

process.nextTick vs setImmediate

// nextTick has higher priority than promise microtasks
process.nextTick(() => console.log(1));
Promise.resolve().then(() => console.log(2));
// Output order: 1, 2

// setImmediate belongs to macrotasks
setImmediate(() => console.log('Macrotask'));

File I/O Optimization

const fs = require('fs');

// Use setImmediate to decompose large file processing
function processLargeFile(path) {
  fs.readFile(path, (err, data) => {
    const chunks = splitData(data);
    
    function processChunk(index) {
      if(index >= chunks.length) return;
      
      doWork(chunks[index]);
      setImmediate(() => processChunk(index + 1));
    }
    
    processChunk(0);
  });
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.