摘要:高級定時器高級技巧異步首先,中沒有代碼是立即執(zhí)行的,而是一旦進程空閑則立即執(zhí)行。針對第二種問題,使用定時器是解決方法之一。為定時器設定的時間間隔使得進程有時間在處理項目的事件之間轉入空閑。該函數首先清除之前設置的任何定時器。
title: 高級定時器
date: 2016-12-13
tag: JS高級技巧
首先,JavaScript 中沒有代碼是立即執(zhí)行的,而是一旦進程空閑則立即執(zhí)行。
進程何時空閑,取決于上一個執(zhí)行隊列的執(zhí)行時間,而與此對應的是隨著頁面中生命周期的推移而產生的代碼執(zhí)行順序隊列。
定時器對隊列的工作方式是,當設定的時間過去以后將代碼插入隊列,但不代表代碼會被立即執(zhí)行。
0x01 重復定時器很多情況下,我們都需要使用 setInterval() 重復的執(zhí)行同一段代碼去做同一件事情,而在這時,最大的問題在于定時器可能在代碼再次被添加到隊列之前還沒有被執(zhí)行完成,從而導致某些間隔被跳過或者多個定時器的代碼執(zhí)行時間間隔被縮短。
為了避免以上缺點,可以使用鏈式調用 setTimeout() 模式
setTimeout(function(){ // do something setTimeout(arguments.callee, interval); }, interval)
一個例子:
setTimeout(function(){ $("#block").css({ "left": $("#block").position().left -1, }) if($("#block").position().left > 0){ setTimeout(arguments.callee, 30); } }, 30)0x01 數組分塊
為了防止惡意程序猿將用戶的計算機搞掛,瀏覽器對 JavaScript 能夠使用的資源進行了限制,如果代碼的運行時間超過特定時間或者特定語句數量就不讓其繼續(xù)運行。
而腳本運行時間過長的兩個主要原因是:1)過長,過深嵌套的函數調用;2)進行大量處理的循環(huán)。
針對第二種問題,使用定時器是解決方法之一。使用定時器分隔循環(huán),是一種叫作 數組分塊(array chunking) 的技術。
在數組分塊模式中,array 變量本質上就是一個 “代辦事項” 列表,它包含了要處理的項目,而 shift() 可以獲取隊列中下一個要處理的項目,然后將其傳遞個某個函數。當隊列中還剩下其它項目時,則設置另一個定時器,并通過 arguments.callee 調用同一個匿名函數。
function chunk(array, process, context){ setTimeout(function(){ var item = array.shift() process.call(context, item) if(array.length > 0){ setTimeout(arguments.callee, 100) } }, 100) }
chunk() 方法接收三個參數: 要處理項目的數組,用于處理項目的函數,可選的運行該函數的環(huán)境。
在函數內部,通過 call() 調用 process() 函數,這樣可以設置一個合適的執(zhí)行環(huán)境。為定時器設定的時間間隔使得 JavaScript 進程有時間在處理項目的事件之間轉入空閑。
調用實例:
var data = [12,124,343,56,76767,43,654,34645,56456,767,4645] function printValue(item){ var div = $("#block").html() $("#block").html(div + item + "
") } chunk(data, printValue)
如上,函數 printValue() 將 data 數組中的每個值輸出到一個 div 元素中。由于函數處于全局作用域中,因此無需給 chunk() 函數傳遞 context 對象。
如果想保持原數組不變,則應將該數組的克隆傳遞給 chunk()
chunk(data.concat(), printValue)
調用某個數組的.contact(),如果不傳遞任何參數,將返回和原來數組中項目一樣的數組。
0x02 函數節(jié)流函數節(jié)流 的基本思想是指,某些代碼不可以在沒有間斷的情況下連續(xù)重復的執(zhí)行。
瀏覽器中某些計算和處理的代價要比其他的昂貴很多,比如,DOM 操作比非 DOM 交互需要更多的內存和 CPI 時間,而進行過多的 DOM 相關操作可能導致瀏覽器掛起甚至崩潰,對于這種問題,可以使用定時器對函數進行節(jié)流。
函數節(jié)流的基本模式可以簡化如下:
function throttle(method, context){ clearTimeout(method.tId) method.tId = setTimeout(function(){ method.call(context) }, 100) }
throttle() 函數接收兩個參數: 要執(zhí)行的函數以及在哪個作用域中執(zhí)行。該函數首先清除之前設置的任何定時器。定時器 ID 是存儲在函數的 tId 屬性中的,當然,首次將方法傳遞給 throttle 函數可能并不存在該屬性。然后定義一個新的定時器,并將 ID 存儲在 tId 屬性中。而 call() 用來確保方法在適當的環(huán)境中執(zhí)行。如果沒有給出第二個參數,那么就在全局作用域內執(zhí)行該方法。
在 setTimeout() 中用到的函數其執(zhí)行環(huán)境總是 window
throttle 方法調用實例:
function resizeDiv(){ var div = document.querySelector("#block") div.style.height = div.offsetWidth + "px" } window.onresize = function(){ throttle(resizeDiv) }
如上,為了保證在 resize 事件中瀏覽不會進行高頻率,或者多次計算,我們給 window.onresize 綁定了一個函數,在該函數調用了 throttle 方法,從而在窗口大小發(fā)生改變的時候是 div#block 的高度與其寬度保持一致。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/91349.html
摘要:圖二解讀定時器可以在指定時間把定時器代碼加入待執(zhí)行隊列,但并不能保證代碼執(zhí)行時機,待執(zhí)行隊列中的代碼要等進程空閑時才能執(zhí)行。也就是說定時器每隔間隔觸發(fā)一次,嘗試加入隊列,擁堵時段將直接忽略本次操作。 圖片出自JS高程(第三版) showImg(https://segmentfault.com/img/bVbgC3V?w=1337&h=313); 圖一解讀:JS運行于單線程的環(huán)境中:頁面...
摘要:關于定時器要記住的最重要的事情是指定的時間間隔表示何時將定時器的代碼添加到隊列,而不是何時實際執(zhí)行代碼。多個定時器之間的執(zhí)行間隔會比預期的小解決辦法處理中數組分塊,,函數節(jié)流,實際進行處理的方法實際執(zhí)行的代碼初始處理調用的方法 一、高級函數 安全類型檢測 Object.protitype.toString.call(value) 作用域安全的構造函數 function Pers...
摘要:下面通過幾個的定時器示例以及相關源碼來分析在中,功能到底是怎么實現(xiàn)的。我們知道,中的定時器并不同于計算機底層的定時中斷。補充資料在高級程序設計第三版第章高級技巧中對高級定時器以及有較詳細的討論。至此,這類定時器函數已經可以為所用了。 上一篇博文提到,在Node中timer并不是通過新開線程來實現(xiàn)的,而是直接在event loop中完成。下面通過幾個JavaScript的定時器示例以及N...
摘要:和的定義是指多少時間之后將回調函數加入到的執(zhí)行隊列之中回調函數是否立即執(zhí)行取決于當前的執(zhí)行隊列是否空閑。比較好的例子如下回調函數執(zhí)行其他操作假如內部的執(zhí)行時間為那么的回調函數至少要等待才執(zhí)行。 1、惰性加載函數 (判斷各個瀏覽器中是否支持某個屬性) function addEvent(elem, type, handler){ if(elem.addEventListener...
摘要:閉包閉包是指有權訪問另一個函數作用域中的變量的函數當某個函數被調用時,會創(chuàng)建一個執(zhí)行環(huán)境及相應的作用域鏈。要注意通過第句聲明的這個方法屬于構造函數生成的對象,而不屬于構造函數的變量對象,也就是說,并不存在于作用域鏈中。 看到評論里有仁兄建議我試試箭頭函數,真是受寵若驚,本來寫這篇文章也只是想記錄寫要點給自己日后看的。今天早上看到一篇總結javascript中this的文章JavaScr...
閱讀 808·2021-10-14 09:43
閱讀 2133·2021-09-30 09:48
閱讀 3456·2021-09-08 09:45
閱讀 1102·2021-09-02 15:41
閱讀 1898·2021-08-26 14:15
閱讀 786·2021-08-03 14:04
閱讀 2985·2019-08-30 15:56
閱讀 3080·2019-08-30 15:52