首頁 > web前端 > js教程 > 如何在JavaScript中安排背景任務

如何在JavaScript中安排背景任務

William Shakespeare
發布: 2025-02-18 09:04:11
原創
273 人瀏覽過

How to Schedule Background Tasks in JavaScript

核心要點

  • JavaScript 是一種阻塞式語言,一次只能執行一項任務,這可能導致長時間運行的腳本使瀏覽器無響應。但是,可以安排不太重要的後台任務運行,而不會直接影響用戶體驗。
  • requestIdleCallback 是一個 API,允許在瀏覽器空閒時安排非必要任務,類似於 requestAnimationFrame 的功能。它可以與超時選項一起使用,以確保任務在設定的時間範圍內運行,即使瀏覽器不空閒也是如此。
  • requestIdleCallback 是一項實驗性功能,瀏覽器支持有限,不適用於執行時間不可預測的任務或解決 Promise 的任務。對於不支持的瀏覽器或需要直接訪問 DOM 的任務,可以使用 Web Workers 或 setTimeout 等替代方案。

如果忘記 JavaScript 的其他所有內容,請永遠記住這一點:它會阻塞。想像一下,一個神奇的處理精靈讓您的瀏覽器工作。無論是渲染 HTML、響應菜單命令、在屏幕上繪圖、處理鼠標點擊還是運行 JavaScript 函數,所有這些都由單個精靈處理。像我們大多數人一樣,精靈一次只能做一件事情。如果我們向精靈扔很多任務,它們會被添加到一個大的待辦事項列表中,並按順序處理。當精靈遇到腳本標籤或必須運行 JavaScript 函數時,其他所有內容都會停止。代碼(如果需要)將被下載並在處理進一步事件或渲染之前立即運行。這是必要的,因為您的腳本可以執行任何操作:加載更多代碼、刪除每個 DOM 元素、重定向到另一個 URL 等。即使有兩個或多個精靈,其他精靈也需要在第一個精靈處理您的代碼時停止工作。這就是阻塞。這就是長時間運行的腳本導致瀏覽器無響應的原因。您通常希望 JavaScript 盡快運行,因為代碼會初始化窗口小部件和事件處理程序。但是,還有一些不太重要的後台任務不會直接影響用戶體驗,例如:

  • 記錄分析數據
  • 將數據發送到社交網絡(或添加 57 個“分享”按鈕)
  • 預取內容
  • 預處理或預渲染 HTML

這些不是時間關鍵型任務,但是為了使頁面保持響應速度,它們不應該在用戶滾動或與內容交互時運行。一種選擇是使用 Web Workers,它可以在單獨的線程中並發運行代碼。這是預取和處理的一個很好的選擇,但您不允許直接訪問或更新 DOM。您可以在自己的腳本中避免這種情況,但您無法保證第三方腳本(例如 Google Analytics)永遠不需要它。另一種可能性是 setTimeout,例如 setTimeout(doSomething, 1);。瀏覽器將在其他立即執行的任務完成後執行 doSomething() 函數。實際上,它被放在待辦事項列表的底部。不幸的是,無論處理需求如何,該函數都會被調用。

requestIdleCallback

requestIdleCallback 是一個新的 API,旨在在瀏覽器喘息的那些時刻安排非必要的後台任務。它讓人想起 requestAnimationFrame,它會在下一次重繪之前調用一個函數來更新動畫。您可以在此處閱讀有關 requestAnimationFrame 的更多信息:使用 requestAnimationFrame 進行簡單動畫

我們可以像這樣檢測是否支持 requestIdleCallback

if ('requestIdleCallback' in window) {
  // requestIdleCallback 受支持
  requestIdleCallback(backgroundTask);
} else {
  // 不支持 - 执行其他操作
  setTimeout(backgroundTask1, 1);
  setTimeout(backgroundTask2, 1);
  setTimeout(backgroundTask3, 1);
}
登入後複製
登入後複製

您還可以使用超時(以毫秒為單位)指定選項對象參數,例如:

requestIdleCallback(backgroundTask, { timeout: 3000 });
登入後複製
登入後複製

這確保您的函數在最初三秒鐘內被調用,無論瀏覽器是否空閒。 requestIdleCallback 只調用您的函數一次,並傳遞一個具有以下屬性的截止日期對象:

  • didTimeout — 如果可選超時觸發,則設置為 true
  • timeRemaining() — 返回可執行任務的剩餘毫秒數的函數

timeRemaining() 將為您的任務分配不超過 50 毫秒的運行時間。它不會停止超過此限制的任務,但最好再次調用 requestIdleCallback 來安排進一步的處理。讓我們創建一個簡單的示例,它按順序執行多個任務。任務作為函數引用存儲在數組中:

// 要运行的函数数组
var task = [
  background1,
  background2,
  background3
];

if ('requestIdleCallback' in window) {
  // requestIdleCallback 受支持
  requestIdleCallback(backgroundTask);
} else {
  // 不支持 - 尽快运行所有任务
  while (task.length) {
    setTimeout(task.shift(), 1);
  }
}

// requestIdleCallback 回调函数
function backgroundTask(deadline) {
  // 如果可能,运行下一个任务
  while (deadline.timeRemaining() > 0 && task.length > 0) {
    task.shift()();
  }

  // 如果需要,安排进一步的任务
  if (task.length > 0) {
    requestIdleCallback(backgroundTask);
  }
}
登入後複製
登入後複製

requestIdleCallback 中不應該執行的操作?

正如 Paul Lewis 在他關於此主題的博客文章中所指出的那樣,您在 requestIdleCallback 中執行的工作應該分成小塊。它不適用於執行時間不可預測的任何內容(例如操作 DOM,最好使用 requestAnimationFrame 回調來完成)。您還應該注意解決(或拒絕)Promise,因為回調將在空閒回調完成後立即執行,即使沒有更多剩餘時間也是如此。

requestIdleCallback 瀏覽器支持

requestIdleCallback 是一項實驗性功能,規範仍在不斷變化,因此當您遇到 API 更改時不要感到驚訝。它在 Chrome 47 中受支持……這應該在 2015 年底之前可用。 Opera 也應該很快獲得此功能。 Microsoft 和 Mozilla 都正在考慮使用該 API,而且聽起來很有希望。蘋果公司像往常一樣沒有消息。如果您想今天嘗試一下,最好的辦法是使用 Chrome Canary(Chrome 的一個更新版本,測試不如前者完善,但擁有最新的炫酷功能)。 Paul Lewis(上面提到)創建了一個簡單的 requestIdleCallback shim。這實現了 API 的描述,但它不是可以模擬瀏覽器空閒檢測行為的 polyfill。它採用像上面的示例一樣使用 setTimeout 的方法,但如果您想在沒有對象檢測和代碼分叉的情況下使用 API,這是一個不錯的選擇。雖然今天的支持有限,但 requestIdleCallback 可能是幫助您最大限度地提高網頁性能的有趣工具。但您怎麼看呢?我很樂意在下面的評論部分聽到您的想法。

關於在 JavaScript 中調度後台任務的常見問題解答 (FAQ)

什麼是 JavaScript 中的後台任務 API?

JavaScript 中的後台任務 API 是一種強大的工具,允許開發人員安排後台運行的任務,即使主線程空閒也是如此。此 API 特別適用於需要大量計算或網絡請求的任務,因為它允許執行這些任務而不會阻塞主線程並可能導致糟糕的用戶體驗。後台任務 API 是現代瀏覽器提供的更大 Web API 的一部分,與傳統的 setTimeoutsetInterval 方法相比,它提供了一種更高效且更注重性能的處理後台任務的方法。

後台任務 API 與 setTimeoutsetInterval 有何不同?

setTimeoutsetInterval 函數是 JavaScript 中用於安排任務在特定延遲後或以定期間隔運行的傳統方法。但是,這些方法有一些限制,尤其是在性能方面。它們在主線程上運行,這意味著如果它們花費太長時間才能完成,它們可能會阻塞其他任務並可能導致糟糕的用戶體驗。另一方面,後台任務 API 在後台運行任務,與主線程分開。這意味著它可以處理更密集的任務,而不會影響主線程的性能。

我可以在所有瀏覽器中使用後台任務 API 嗎?

後台任務 API 是現代瀏覽器提供的 Web API 的一個相對較新的補充,因此,它可能並非在所有瀏覽器中都受支持。在您的項目中計劃使用任何 API 時,始終最好檢查您計劃使用的 API 的當前支持級別。像 Can I Use 這樣的網站提供了有關不同瀏覽器中各種 API 的支持級別的最新信息。

如何使用後台任務 API 安排後台運行的任務?

要使用後台任務 API 安排任務,您可以使用 requestIdleCallback 方法。此方法將回調函數作為其第一個參數,該函數將在瀏覽器空閒時執行。這是一個基本示例:

if ('requestIdleCallback' in window) {
  // requestIdleCallback 受支持
  requestIdleCallback(backgroundTask);
} else {
  // 不支持 - 执行其他操作
  setTimeout(backgroundTask1, 1);
  setTimeout(backgroundTask2, 1);
  setTimeout(backgroundTask3, 1);
}
登入後複製
登入後複製

如何取消已安排的後台任務?

如果您需要取消使用 requestIdleCallback 方法安排的後台任務,可以使用 cancelIdleCallback 方法。此方法將 requestIdleCallback 返回的 ID 作為其參數。這是一個示例:

requestIdleCallback(backgroundTask, { timeout: 3000 });
登入後複製
登入後複製

requestIdleCallback 中的超時選項有什麼用?

requestIdleCallback 中的超時選項用於指定瀏覽器在運行回調之前應等待的最大時間(以毫秒為單位),即使它不空閒也是如此。如果您的後台任務需要在特定時間範圍內運行,這將非常有用。

如何處理後台任務中的錯誤?

處理使用後台任務 API 安排的後台任務中的錯誤類似於處理任何其他 JavaScript 代碼中的錯誤。您可以使用 try/catch 塊來捕獲在任務執行期間發生的任何錯誤。這是一個示例:

// 要运行的函数数组
var task = [
  background1,
  background2,
  background3
];

if ('requestIdleCallback' in window) {
  // requestIdleCallback 受支持
  requestIdleCallback(backgroundTask);
} else {
  // 不支持 - 尽快运行所有任务
  while (task.length) {
    setTimeout(task.shift(), 1);
  }
}

// requestIdleCallback 回调函数
function backgroundTask(deadline) {
  // 如果可能,运行下一个任务
  while (deadline.timeRemaining() > 0 && task.length > 0) {
    task.shift()();
  }

  // 如果需要,安排进一步的任务
  if (task.length > 0) {
    requestIdleCallback(backgroundTask);
  }
}
登入後複製
登入後複製

我可以在 Node.js 中使用後台任務 API 嗎?

後台任務 API 是現代瀏覽器提供的 Web API 的一部分,因此默認情況下它在 Node.js 中不可用。但是,還有其他方法可以在 Node.js 中運行後台任務,例如使用工作線程或子進程。

我可以將後台任務 API 與 Promise 或 async/await 一起使用嗎?

後台任務 API 不返回 Promise,因此不能直接與 async/await 一起使用。但是,如果您需要在異步上下文中使用它,則可以將 requestIdleCallback 方法包裝在 Promise 中。這是一個示例:

window.requestIdleCallback(() => {
  // 您的后台任务在此处
});
登入後複製

後台任務 API 的一些用例是什麼?

後台任務 API 對於任何需要大量計算或網絡請求的任務都很有用,因為它允許執行這些任務而不會阻塞主線程。用例的一些示例可能包括從 API 獲取和處理數據、執行複雜的計算或根據用戶交互更新 UI。

以上是如何在JavaScript中安排背景任務的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板