Chia nhỏ các tác vụ cần nhiều thời gian

Tính năng web: Scheduler API

Các phép tính nặng hoặc vòng lặp dài có thể chặn luồng chính, khiến trang không phản hồi. Để ngăn chặn điều này, bạn nên định kỳ trả lại quyền kiểm soát cho trình duyệt. API scheduler.yield() cho phép bạn tạm dừng một tác vụ cần nhiều thời gian và để trình duyệt xử lý hoạt động đầu vào của người dùng hoặc kết xuất trước khi tiếp tục.

Chia nhỏ các tác vụ cần nhiều thời gian

Sử dụng scheduler.yield() bên trong các hàm không đồng bộ để chia nhỏ công việc.

async function processLargeArray(items) {
  // DO: Set a time-based deadline 50 milliseconds into the future. 50
  // milliseconds is the boundary for when a task becomes a long task.
  let deadline = performance.now() + 50; // 50ms budget

  for (const item of items) {
    // Process the item
    processItem(item);
    
    // MANDATORY: Yield to the main thread periodically to keep the UI
    // responsive. This can be done by checking if the deadline set earlier
    // has been exceeded. When it has been, yield, then reset the deadline
    // another 50 milliseconds into the future.
    if (performance.now() >= deadline) {
      await scheduler.yield();
      deadline = performance.now() + 50;
    }
  }
}

Chiến lược dự phòng

Một số trình duyệt có thể không hỗ trợ scheduler API. Bạn PHẢI triển khai phương án dự phòng bằng setTimeout để đảm bảo mã thực thi mà không bị lỗi.

Dự phòng cho scheduler.yield()

async function processLargeArrayWithFallback(items) {
  // DO: Set a time-based deadline 50 milliseconds into the future.
  let deadline = performance.now() + 50;

  for (const item of items) {
    processItem(item);
    
    // MANDATORY: Yield to the main thread periodically to keep the UI responsive.
    if (performance.now() >= deadline) {
      // DO: Feature detect scheduler.yield
      if ('scheduler' in window && 'yield' in window.scheduler) {
        await scheduler.yield();
      } else {
        // DO: Fallback to setTimeout for older browsers
        await new Promise(resolve => setTimeout(resolve, 0));
      }
      deadline = performance.now() + 50;
    }
  }
}