淺談JavaScript函數(shù)節(jié)流
瀏覽器中某些計(jì)算和處理要比其他的昂貴的多。例如,DOM操作比起非DOM交互需要更多的內(nèi)存和CPU時(shí)間。連續(xù)嘗試進(jìn)行過(guò)多的DOM相關(guān)操作可能會(huì)導(dǎo)致 瀏覽器掛起,有時(shí)候甚至?xí)罎?。尤其在IE中使用onresize事件處理程序的時(shí)候容易發(fā)生,當(dāng)調(diào)整瀏覽器大小的時(shí)候,該事件連續(xù)觸發(fā)。在 onresize事件處理程序內(nèi)部如果嘗試進(jìn)行DOM操作,其高頻率的更改可能會(huì)讓瀏覽器崩潰。
函數(shù)節(jié)流背后的基本思想是,某些代碼不可以在沒(méi)有間斷的情況連續(xù)重復(fù)執(zhí)行。第一次調(diào)用函數(shù),創(chuàng)建一個(gè)定時(shí)器,在指定的時(shí)間間隔之后運(yùn)行代碼。當(dāng)?shù)诙握{(diào)用 該函數(shù)時(shí),它會(huì)清除前一次的定時(shí)器并設(shè)置另一個(gè)。如果前一個(gè)定時(shí)器已經(jīng)執(zhí)行過(guò)了,這個(gè)操作就沒(méi)有任何意義。然而,如果前一個(gè)定時(shí)器尚未執(zhí)行,其實(shí)就是將其 替換為一個(gè)新的定時(shí)器。目的是只有在執(zhí)行函數(shù)的請(qǐng)求停止了一段時(shí)間之后才執(zhí)行。
function throttle ( method , context ){ clearTimeout ( method.tId ); method.tId = setTimeout ( function () { method.call ( context ); } , 100); }
應(yīng)用舉例:
假設(shè)有一個(gè)<div/>元素需要保持它的高度始終等同于寬度,可作如下編碼:
function resizeDiv(){ var div = document.getElementById("mydiv"); div.style.height = div.offsetWidth + "px"; } window.onresize = function(){ throttle(resizeDiv); }
這里,調(diào)整大小的功能被放入了一個(gè)叫做resizeDiv的單獨(dú)函數(shù)中,然后onresize事件處理程序調(diào)用throttle()并傳入 resizeDiv函數(shù),而不是直接調(diào)用resizeDiv()。多數(shù)情況下,用戶(hù)是感覺(jué)不到變化的,雖然給瀏覽器節(jié)省的計(jì)算可能非常大。
下面是其他網(wǎng)友的補(bǔ)充
今天主要寫(xiě)寫(xiě)我們平時(shí)工作中需要的函數(shù)節(jié)流。可能有的朋友對(duì)函數(shù)節(jié)流沒(méi)有意識(shí)。其實(shí),在工作中,很多場(chǎng)景都需要我們進(jìn)行js的節(jié)流。最常見(jiàn)的是屏幕伸縮resize,以及touchmove或者scroll等事件的時(shí)候。大家不知道有沒(méi)有看我之前寫(xiě)的文章!jquery判斷頁(yè)面滾動(dòng)條上滾下滾,touchmove的滑動(dòng)方向,大家在使用這些例子的時(shí)候,會(huì)發(fā)現(xiàn)頁(yè)面不停的觸發(fā)touchmove或者scroll因?yàn)檫@里沒(méi)有關(guān)系到頁(yè)面的重繪,因此,我在這里沒(méi)有使用javascript函數(shù)節(jié)流。但是,當(dāng)我們使用window.onresize的時(shí)候,也會(huì)不停的觸發(fā)resize事件!這里就會(huì)關(guān)系到頁(yè)面的重新繪制問(wèn)題了。因此,在window的resize的時(shí)候,我們推薦大家使用函數(shù)節(jié)流的方式!
javascript函數(shù)節(jié)流簡(jiǎn)介
假如你對(duì)我上面一大坨文字感到頭大,沒(méi)關(guān)系,我在這里簡(jiǎn)單舉例說(shuō)明一下函數(shù)節(jié)流吧!例如當(dāng)我們使用
$(window).resize(function(){ console.log("haorooms window resize"); })
會(huì)發(fā)現(xiàn):
這里會(huì)輸出好多次。我們簡(jiǎn)單的縮小一下窗口,就會(huì)不停的觸發(fā)!
這樣在div很多的時(shí)候,頁(yè)面不停重繪,要是遇到版本比較低的IE等,很可能會(huì)出現(xiàn)瀏覽器崩潰的現(xiàn)象!為了避免這種情況,我們可以用函數(shù)節(jié)流的方式?;镜乃枷胧牵旱谝淮握{(diào)用函數(shù)的時(shí)候,我們創(chuàng)建一個(gè)定時(shí)器,在指定時(shí)間間隔之后運(yùn)行代碼,第二次調(diào)用的時(shí)候,會(huì)清楚前一個(gè)定時(shí)器,并重新設(shè)置一個(gè)。如果前一個(gè)定時(shí)器已經(jīng)執(zhí)行過(guò)了,那么這個(gè)操作就沒(méi)有有意了,如果定時(shí)器尚未執(zhí)行,就會(huì)將其替換為一個(gè)新的定時(shí)器。目的是在執(zhí)行函數(shù)停止了一段時(shí)間之后再執(zhí)行。
用對(duì)象的方式可以如下寫(xiě):
var haoroomstest={ timeoutId:null, performProcessing:function(){ console.log("resize"); }, process:function(){ clearTimeout(this.timeoutId); var that=this; this.timeoutId=setTimeout(function(){ that.performProcessing(); },500) } }
這樣之后,我們?cè)儆茫?/p>
$(window).resize(function(){ haoroomstest.process(); })
這樣就會(huì)減少請(qǐng)求,減少dom重繪,達(dá)到節(jié)流的目的!
函數(shù)節(jié)流其他方式
除了我們運(yùn)用對(duì)象的方式,網(wǎng)上及資料中也介紹了關(guān)于函數(shù)節(jié)流的其他方法和方式,我下面簡(jiǎn)單介紹幾種!
函數(shù)方式一
function throttle(method,context){ clearTimeout(method.tId); method.tId=setTimeout(function(){ method.call(context); },100); }
我們?nèi)缦率褂?/p>
function resizeDIv(){ console.log("haorooms") } $(window).resize(function(){ throttle(resizeDIv) })
和上面對(duì)象實(shí)現(xiàn)了同樣的效果!
函數(shù)方式二
網(wǎng)上還有一種比較流行的節(jié)流方式,我在這里寫(xiě)一下!
function throttle(method,delay){ var timer=null; return function(){ var context=this, args=arguments; clearTimeout(timer); timer=setTimeout(function(){ method.apply(context,args); },delay); } }
然后可以這么寫(xiě):
function resizeDIv(){ console.log("haorooms") } window.onresize=throttle(resizeDIv,500);
新需求
我們?cè)谧瞿:阉髦悄苈?lián)想提示的時(shí)候,會(huì)在input上面綁定keyup事件。但是我又不想觸發(fā)的那么頻繁,用上面的方式就會(huì)有問(wèn)題。因此,在上面的函數(shù)基礎(chǔ)上稍加改動(dòng),如下:
function throttle(method,delay,duration){ var timer=null, begin=new Date(); return function(){ var context=this, args=arguments, current=new Date();; clearTimeout(timer); if(current-begin>=duration){ method.apply(context,args); begin=current; }else{ timer=setTimeout(function(){ method.apply(context,args); },delay); } } }
這樣觸發(fā)就不會(huì)有之前那么頻繁了!
- JS函數(shù)節(jié)流和函數(shù)防抖問(wèn)題分析
- JavaScript函數(shù)節(jié)流和函數(shù)防抖之間的區(qū)別
- 淺析JavaScript 函數(shù)防抖和節(jié)流
- 詳解JS函數(shù)防抖
- 如何解決js函數(shù)防抖、節(jié)流出現(xiàn)的問(wèn)題
- JavaScript性能優(yōu)化之函數(shù)節(jié)流(throttle)與函數(shù)去抖(debounce)
- JavaScript函數(shù)節(jié)流概念與用法實(shí)例詳解
- JS中setTimeout的巧妙用法前端函數(shù)節(jié)流
- 如何理解JS函數(shù)防抖和函數(shù)節(jié)流
相關(guān)文章
有關(guān)于JS輔助函數(shù)inherit()的問(wèn)題
本篇為大家介紹有關(guān)于JS輔助函數(shù)inherit()的一些問(wèn)題。2013-04-04Uglifyjs(JS代碼優(yōu)化工具)入門(mén) 安裝使用
Uglify JS 是一個(gè)服務(wù)端node.js的壓縮程序。需要的朋友可以測(cè)試下2012-03-03Javascript學(xué)習(xí)筆記之 對(duì)象篇(四) : for in 循環(huán)
如同 in 運(yùn)算符一樣,使用 for in 循環(huán)遍歷對(duì)象屬性時(shí),也將往上遍歷整個(gè)原型鏈。2014-06-06JavaScript中的Math.atan2()方法使用詳解
這篇文章主要介紹了JavaScript中的Math.atan2()方法使用詳解,是JS入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-06-06JavaScript中的this,call,apply使用及區(qū)別詳解
本文結(jié)合基本javascript的權(quán)威書(shū)籍中的內(nèi)容,根據(jù)自己的理解,通過(guò)相關(guān)示例向大家展示了javascript中this,call,apply使用及區(qū)別,非常的細(xì)致全面,希望大家能夠喜歡。2016-01-01深入理解JavaScript高級(jí)之詞法作用域和作用域鏈
這篇文章主要介紹了JavaScript高級(jí)之詞法作用域和作用域鏈,有需要的朋友可以參考一下2013-12-12javascript學(xué)習(xí)筆記(四)function函數(shù)部分
本文主要介紹了函數(shù)的調(diào)用方式、返回函數(shù)的函數(shù)、創(chuàng)建匿名函數(shù)、javascript創(chuàng)建動(dòng)態(tài)函數(shù)、回調(diào)函數(shù)、方法和函數(shù)的區(qū)別、js全局函數(shù)、函數(shù)的幾個(gè)作用、prototype屬性、高階函數(shù),非常實(shí)用,有需要的參考下2014-09-09國(guó)內(nèi)常用的js類(lèi)庫(kù)大全(CDN公共庫(kù))
羅列這類(lèi)js類(lèi)庫(kù)希望能幫助到大家,下面類(lèi)庫(kù)都支持CDN,所以不用擔(dān)心速度問(wèn)題,就算某個(gè)節(jié)點(diǎn)慢也不會(huì)影響全國(guó)其他地區(qū)的訪問(wèn)速度,支持jQuery,Bootstrap,angular,zepto等js庫(kù)的CDN地址2020-06-06