一直認爲學會的東西后來才發現瞭解的僅是一點點~還有不少須要我去了解、探索,從書籍、博客、團隊的夥伴、視頻等等一系列均可以學到不少。只要你想就會變得更增強大,不斷積累本身吧~~~javascript
今天就瞭解一下定時器,先看看下面代碼java
document.onclick = function(){
setTimeout(function() { console.log("111"); }, 100); setTimeout(function(){ console.log("222"); }, 250); };
點擊後,控制檯輸出111,222這是毋庸置疑的,那麼,「222」在點擊多長時間以後輸出呢?(忽略代碼的運行時間) 是350ms ???實際上是250ms。ajax
在理解爲何以前首先要知道,在javascript中定時器是異步執行,異步???解釋一下:數組
js是任務執行環境是單線程,爲了解決單線程帶來的麻煩,js將任務執行模式分爲兩種,同步和異步。同步是指任務在主線程上等待運行,而異步是指任務在任務隊列中等待,主線程何時爲空就執行任務隊列。那麼,什麼樣的任務是放在任務隊列中的呢?定時器、ajax、各類事件(如點擊、滑動等事件)~~ps:我只知道這些啦~~~~~瀏覽器
瞭解這些以後,再來講一下上面的答案爲何是250ms。異步
定時器最重要的就是記住,指定的時間間隔表示什麼時候將定時器的代碼添加到隊列中,而不是什麼時候實際執行代碼。函數
所以,100ms時將第一個setTimeout的任務放入任務隊列中,250ms時將第二個setTimeout任務放入任務隊列中(注意這個250ms是相對於開始,即100ms以後的150ms)。因此,答案就是250ms啦!spa
再來講一下setInterval(重複定時器)線程
重複定時器有兩個問題code
1>某些間隔會被跳過
2>多個定時器的代碼執行之間的間隔會比預期的小
舉個例子,onclick事件處理程序使用setInterval()設置200ms的間隔,而事件處理須要300ms完成,來看一下這段代碼的進程時間線
從圖中能夠看出,5ms時建立了間隔200ms的定時器,205ms時定時器代碼添加到隊列中,可是,onclick事件處理程序須要300ms,定時器須要等待事件處理程序以後才能夠執行(setTimeout也遵循這種方式,只不過爲了說明前面的問題,因此忽略了事件處理程序的時間,前面也已經標註)所以,在300ms後才能夠執行第一個定時器代碼。但是,在405ms時又在隊列中添加了另一個副本,在605ms時,第一個定時器代碼仍在運行,並且隊列中還有一個定時器正在等待,因此此時的定時器代碼不會被添加到隊列中。
因此,咱們在使用setInterval()時常常發現它計算的時間不太對,爲了彌補這兩個缺點可使用setTimeout代替重複定時器。
setTimeout(function() {
setTimeout(arguments.callee, interval);
}, interval);
每次函數執行時都會建立新的定時器,第二個定時器使用arguments.callee來獲取當前的執行函數引用,並設置另外一個定時器。這樣作就能夠在定時器代碼執行以前不加入新的定時器代碼,並且保證了下一次定時器代碼執行以前,至少要等待指定的間隔。
利用setTimeout數組分塊
想象一下這種狀況,當處理一些數據時須要對大量的數據進行循環,可想而知,若是單純用for循環這是一件很是可怕的事情。
解決辦法:將處理項目建立一個隊列,使用定時器取出一個要處理的數據,接着再處理另外一個數據
/**
* [chunk description]
* @param {[type]} array [處理項目的數組]
* @param {[type]} process [處理項目的函數]
* @param {[type]} context [可選運行該函數的環境]
* @return {[type]} [description]
*/
function chunk(array, process, context) {
setTimeout(function() { var item = array.shift(); process.call(context, item); if(array.length > 0) { setTimeout(arguments.callee, 100); } }, 100); } //處理的數組 var data = [100, 200, 600, 300, 245]; //處理的函數 function printVlaue(item) { console.log(item); } //調用數組分塊函數 chunk(data, printVlaue);
可是,可是,利用這種方法你必需要考慮你處理的數據不須要同步處理而且不按順序執行,畢竟setTimeout是異步處理。
還有一點還需注意,chunk函數裏處理數據是用shift()函數,會改變原數組的值,所以,若是你還需使用原數組值時,最好將data數組克隆處理。
函數節流
咱們知道js中DOM操做是從document開始查找,因此比非DOM操做須要更多的內存和cpu時間。想象一下,在隨着調整窗口大小觸發resize事件,並獲取某一元素其高度也隨之改變,瀏覽器須要不斷計算其高度大小值,對於瀏覽器來講這是很大的工做量。
解決辦法:節流
var processor = {
tId: null, throttle: function(method, context) { clearTimeout(method.tId); method.tId = setTimeout(function() { method.call(context); }, 100); } }; window.onresize = function() { processor.throttle(resizeDiv); }; function resizeDiv() { var div = document.getElementById('myDiv'); div.style.height = div.offsetWidth + 'px'; console.log(div.style.height); }
首先在throttle方法中先清除以前設置的定時器,而後建立新的定時器,這樣每隔100ms瀏覽器才計算一次高度,又不會影響視覺效果。也能夠適當增長間隔毫秒數。
只要代碼是週期性執行的,均可以使用節流。
嘿嘿~若是有什麼不對的地方求指導~~~~~