即使忘了 JavaScript 的一切知識,也不會忘記:它是阻塞的。
想象一下,你的瀏覽器裡住著一個魔法小精靈,負責瀏覽器的正常運轉。不論渲染 HTML,響應功能表命令,螢幕渲染,處理滑鼠點擊,或者執行 JavaScript 函數,所有事情都歸一個小精靈處理。它哪忙得過來,一次只能處理一件事情。如果同時丟給它一堆任務,它會列一個長長的待辦列表,按順序完成它們。
人們常常希望初始化組件和事件處理的 JavaScript 可以儘快被執行。可是,有些不太重要的背景工作不會直接影響使用者體驗,比如:
記錄統計資料
發送資料到社交網路(或添加‘分享'按鈕)
預先載入內容
預先處理或預渲染 HTML
他們對時序要求不嚴格,但是為了讓頁面仍然響應,直到使用者滾動頁面或者與內容互動時才被執行。
選擇之一是 Web Workers ,它可以在獨立的線程同時執行代碼。用於預先載入和預先處理再好不過,但是你沒有許可權直接存取或更新 DOM。你可以在自己的代碼中避開這點,但是無法保證第三方指令碼比如 Google Analytics 永遠不需要這個。
另一個選擇是setTimeout,比如setTimeout(doSomething, 1);。一旦其它的立即執行任務執行完畢,瀏覽器將執行doSomething()函數。實際上,它被放到了待辦列表的底部。不幸的是,函數將被調用,而不顧處理需求。
#requestIdleCallback
requestIdleCallback 是新API,當瀏覽器稍作喘息的時候,用來執行不太重要的後台計劃任務。 難免讓人想起 requestAnimationFrame ,在下次重繪之前,執行函數更新動畫。 想瞭解更多戳這裡: 使用 requestAnimationFrame 做簡單的動畫 。
requestIdleCallback特性監測:
if ('requestIdleCallback' in window) { // requestIdleCallback supported requestIdleCallback(backgroundTask);}else { // no support - do something else setTimeout(backgroundTask1, 1); setTimeout(backgroundTask2, 1); setTimeout(backgroundTask3, 1);}
也可以指定配置參數對象,比如 timeout,
requestIdleCallback(backgroundTask, { timeout: 3000; });
確保函數在3秒之內調用,不管瀏覽器是否空閑。
deadline對象傳入以下參數時,requestIdleCallback僅執行一次回調:
didTimeout—— 如果可選的 timeout 觸發,則設定為 true
timeRemaining()—— 函數返回執行任務剩餘的毫秒數
timeRemaining()最多分配50ms用於任務的執行,超過這個限制,也不會停止任務,但是,最好重新調用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 回調更好些)。resolving(或者 rejecting)Promises 時也要謹慎,即使沒有更多的剩餘時間,空閑回調完成之後,回呼函數也將立即執行。
#requestIdleCallback 瀏覽器支援情況
requestIdleCallback是實驗性特性,規範仍不穩定,碰到 API 變更時不足為奇。Chrome 47 已支援… 2015年結束前應該可用了。Opera 應該會緊跟其後。Microsoft 和 Mozilla 都在考慮 API 是否應該支援 Promises 。Apple 像往常一樣不鳥。
Paul Lewis(上文提到的)寫了一個簡單的 requestIdleCallback shim ,它可以類比瀏覽器的空閑監測行為,但不是一個 polyfill( shim 和 polyfill 的區別 )。
requestIdleCallback shim代碼如下:
/*! * Copyright Google Inc. All rights reserved. * * Licensed under the Apache License, Version . (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing * permissions and limitations under the License. *//* * @see https://developers.google.com/web/updates///using-requestidlecallback */window.requestIdleCallback = window.requestIdleCallback || function (cb) { var start = Date.now(); return setTimeout(function () { cb({ didTimeout: false, timeRemaining: function () { return Math.max(, - (Date.now() - start)); } }); }, ); }window.cancelIdleCallback = window.cancelIdleCallback || function (id) { clearTimeout(id); }
ps: 如何運行計劃任務
1、運行 GPEDIT.MSC
2、選擇電腦配置
--- Windows 設定
--- 安全設定
--- 本地策略
--- 使用者權利指派
雙擊右邊的 從網路訪問此電腦
把需要的使用者名稱添加到列表。
3、 --- 安全設定
---安全選擇
開啟允許伺服器操作員計劃任務
4、-----本地策略
--- 作為批次工作登入
把需要的使用者名稱添加到列表。
5、-----本地策略
--- 允許電腦和使用者被信任以便於委託
把需要的使用者名稱添加到列表。
最好是administrator使用者。
如果任務計劃無法啟動,提示代碼:0X80041315
解決方案:這有兩種可能,一是系統中的“Task Scheduler”服務沒有啟動,你可在運行中鍵入“services.msc”,查看“Task Scheduler”服務是否被設定成了“已禁用”,若是,只要雙擊它將啟動類型改為“自動”,重新設定一個計劃任務就可以執行了。
如果你當前賬戶設定了自動登入,而其登入密碼又為空白,也有可能導致任務計劃不能按時執行,在XP專業版中,需要運行“gpedit.msc”來編輯組策略:展開“電腦配置→Windows設定→安全設定→本機電腦策略→安全選項”;雙擊右側的“賬戶:使用空白密碼的本地賬戶只允許進行控制台登入”項,在彈出對話方塊中選擇“已禁用”。