成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

JS進(jìn)階篇--JS函數(shù)節(jié)流(throttle)

cpupro / 2919人閱讀

摘要:函數(shù)節(jié)流的原理函數(shù)節(jié)流的原理挺簡(jiǎn)單的,估計(jì)大家都想到了,那就是定時(shí)器。在高級(jí)程序設(shè)計(jì)一書(shū)有介紹函數(shù)節(jié)流,里面封裝了這樣一個(gè)函數(shù)節(jié)流函數(shù),它把定時(shí)器存為函數(shù)的一個(gè)屬性個(gè)人的世界觀不喜歡這種寫(xiě)法。

什么是函數(shù)節(jié)流?

介紹前,先說(shuō)下背景。在前端開(kāi)發(fā)中,有時(shí)會(huì)為頁(yè)面綁定resize事件,或者為一個(gè)頁(yè)面元素綁定拖拽事件(其核心就是綁定mousemove),這種事件有一個(gè)特點(diǎn),就是用戶(hù)不必特地?fù)v亂,他在一個(gè)正常的操作中,都有可能在一個(gè)短的時(shí)間內(nèi)觸發(fā)非常多次事件綁定程序。而大家知道,DOM操作時(shí)很消耗性能的,這個(gè)時(shí)候,如果你為這些事件綁定一些操作DOM節(jié)點(diǎn)的操作的話,那就會(huì)引發(fā)大量的計(jì)算,在用戶(hù)看來(lái),頁(yè)面可能就一時(shí)間沒(méi)有響應(yīng),這個(gè)頁(yè)面一下子變卡了變慢了。甚至在IE下,如果你綁定的resize事件進(jìn)行較多DOM操作,其高頻率可能直接就使得瀏覽器崩潰。

怎么解決?函數(shù)節(jié)流就是一種辦法。話說(shuō)第一次接觸函數(shù)節(jié)流(throttle),還是在看impress源代碼的時(shí)候,impress在播放的時(shí)候,如果窗口大小發(fā)生改變(resize),它會(huì)對(duì)整體進(jìn)行縮放(scale),使得每一幀都完整顯示在屏幕上:

稍微留心,你會(huì)發(fā)現(xiàn),當(dāng)你改變窗體大小的時(shí)候,不管你怎么拉,怎么拽,都沒(méi)有立刻生效,而是在你改變完大小后的一會(huì)兒,它的內(nèi)容才進(jìn)行縮放適應(yīng)??戳嗽创a,它用的就是函數(shù)節(jié)流的方法。

函數(shù)節(jié)流,簡(jiǎn)單地講,就是讓一個(gè)函數(shù)無(wú)法在很短的時(shí)間間隔內(nèi)連續(xù)調(diào)用,只有當(dāng)上一次函數(shù)執(zhí)行后過(guò)了你規(guī)定的時(shí)間間隔,才能進(jìn)行下一次該函數(shù)的調(diào)用。以impress上面的例子講,就是讓縮放內(nèi)容的操作在你不斷改變窗口大小的時(shí)候不會(huì)執(zhí)行,只有你停下來(lái)一會(huì)兒,才會(huì)開(kāi)始執(zhí)行。

函數(shù)節(jié)流的原理

函數(shù)節(jié)流的原理挺簡(jiǎn)單的,估計(jì)大家都想到了,那就是定時(shí)器。當(dāng)我觸發(fā)一個(gè)時(shí)間時(shí),先setTimout讓這個(gè)事件延遲一會(huì)再執(zhí)行,如果在這個(gè)時(shí)間間隔內(nèi)又觸發(fā)了事件,那我們就clear掉原來(lái)的定時(shí)器,再setTimeout一個(gè)新的定時(shí)器延遲一會(huì)執(zhí)行,就這樣。

代碼實(shí)現(xiàn)

明白了原理,那就可以在代碼里用上了,但每次都要手動(dòng)去新建清除定時(shí)器畢竟麻煩,于是需要封裝。在《JavaScript高級(jí)程序設(shè)計(jì)》一書(shū)有介紹函數(shù)節(jié)流,里面封裝了這樣一個(gè)函數(shù)節(jié)流函數(shù):

function throttle(method, context) {
     clearTimeout(methor.tId);
     method.tId = setTimeout(function(){
         method.call(context);
     }, 100);
 }

它把定時(shí)器ID存為函數(shù)的一個(gè)屬性(= =個(gè)人的世界觀不喜歡這種寫(xiě)法)。而調(diào)用的時(shí)候就直接寫(xiě)

window.onresize = function(){
    throttle(myFunc);
}

這樣兩次函數(shù)調(diào)用之間至少間隔100ms。

而impress用的是另一個(gè)封裝函數(shù):

var throttle = function(fn, delay){
     var timer = null;
     return function(){
         var context = this, args = arguments;
         clearTimeout(timer);
         timer = setTimeout(function(){
             fn.apply(context, args);
         }, delay);
     };
 };

它使用閉包的方法形成一個(gè)私有的作用域來(lái)存放定時(shí)器變量timer。而調(diào)用方法為

window.onresize = throttle(myFunc, 100);

兩種方法各有優(yōu)劣,前一個(gè)封裝函數(shù)的優(yōu)勢(shì)在把上下文變量當(dāng)做函數(shù)參數(shù),直接可以定制執(zhí)行函數(shù)的this變量;后一個(gè)函數(shù)優(yōu)勢(shì)在于把延遲時(shí)間當(dāng)做變量(當(dāng)然,前一個(gè)函數(shù)很容易做這個(gè)拓展),而且個(gè)人覺(jué)得使用閉包代碼結(jié)構(gòu)會(huì)更優(yōu),且易于拓展定制其他私有變量,缺點(diǎn)就是雖然使用apply把調(diào)用throttle時(shí)的this上下文傳給執(zhí)行函數(shù),但畢竟不夠靈活。

深化函數(shù)節(jié)流

函數(shù)節(jié)流讓一個(gè)函數(shù)只有在你不斷觸發(fā)后停下來(lái)歇會(huì)才開(kāi)始執(zhí)行,中間你操作得太快它直接無(wú)視你。這樣做就有點(diǎn)太絕了。resize一般還好,但假如你寫(xiě)一個(gè)拖拽元素位置的程序,然后直接使用函數(shù)節(jié)流,那恭喜你,你會(huì)發(fā)現(xiàn)你拖動(dòng)時(shí)元素是不動(dòng)的,你拖完了,它直接閃到終點(diǎn)去。

其實(shí)函數(shù)節(jié)流的出發(fā)點(diǎn),就是讓一個(gè)函數(shù)不要執(zhí)行得太頻繁,減少一些過(guò)快的調(diào)用來(lái)節(jié)流。當(dāng)你改變?yōu)g覽器大小,瀏覽器觸發(fā)resize事件的時(shí)間間隔是多少?我不清楚,個(gè)人猜測(cè)是16ms(每秒64次),反正跟mousemove一樣非常太頻繁,一個(gè)很小的時(shí)間段內(nèi)必定執(zhí)行,這是瀏覽器設(shè)好的,你無(wú)法直接改。而真正的節(jié)流應(yīng)該是在可接受的范圍內(nèi)盡量延長(zhǎng)這個(gè)調(diào)用時(shí)間,也就是我們自己控制這個(gè)執(zhí)行頻率,讓函數(shù)減少調(diào)用以達(dá)到減少計(jì)算、提升性能的目的。假如原來(lái)是16ms執(zhí)行一次,我們?nèi)绻l(fā)現(xiàn)resize時(shí)每50ms一次也可以接受,那肯定用50ms做時(shí)間間隔好一點(diǎn)。

而上面介紹的函數(shù)節(jié)流,它這個(gè)頻率就不是50ms之類(lèi)的,它就是無(wú)窮大,只要你能不間斷resize,刷個(gè)幾年它也一次都不執(zhí)行處理函數(shù)。我們可以對(duì)上面的節(jié)流函數(shù)做拓展:

var throttleV2 = function(fn, delay, mustRunDelay){
     var timer = null;
     var t_start;
     return function(){
         var context = this, args = arguments, t_curr = +new Date();
         clearTimeout(timer);
         if(!t_start){
             t_start = t_curr;
         }
         if(t_curr - t_start >= mustRunDelay){
             fn.apply(context, args);
             t_start = t_curr;
         }
         else {
             timer = setTimeout(function(){
                 fn.apply(context, args);
             }, delay);
         }
     };
 };

在這個(gè)拓展后的節(jié)流函數(shù)升級(jí)版,我們可以設(shè)置第三個(gè)參數(shù),即必然觸發(fā)執(zhí)行的時(shí)間間隔。如果用下面的方法調(diào)用

window.onresize = throttleV2(myFunc, 50, 100);

則意味著,50ms的間隔內(nèi)連續(xù)觸發(fā)的調(diào)用,后一個(gè)調(diào)用會(huì)把前一個(gè)調(diào)用的等待處理掉,但每隔100ms至少執(zhí)行一次。原理也很簡(jiǎn)單,打時(shí)間tag,一開(kāi)始記錄第一次調(diào)用的時(shí)間戳,然后每次調(diào)用函數(shù)都去拿最新的時(shí)間跟記錄時(shí)間比,超出給定的時(shí)間就執(zhí)行一次,更新記錄時(shí)間。

到現(xiàn)在為止呢,當(dāng)我們?cè)陂_(kāi)發(fā)中遇到類(lèi)似的問(wèn)題,一個(gè)函數(shù)可能非常頻繁地調(diào)用,我們有了幾個(gè)選擇:一呢,還是用原來(lái)的寫(xiě)法,頻繁執(zhí)行就頻繁執(zhí)行吧,哥的電腦好;二是用原始的函數(shù)節(jié)流;三則是用函數(shù)節(jié)流升級(jí)版。不是說(shuō)第一種就不好,這要看實(shí)際項(xiàng)目的要求,有些就是對(duì)實(shí)時(shí)性要求高。而如果要求沒(méi)那么苛刻,我們可以視具體情況使用第二種或第三種方法,理論上第二種方法執(zhí)行的函數(shù)調(diào)用最少,性能應(yīng)該節(jié)省最多,而第三種方法則更加地靈活,你可以在性能與體驗(yàn)上探索一個(gè)平衡點(diǎn)。

轉(zhuǎn)載自AlloyTeam:http://www.alloyteam.com/2012...
擴(kuò)展閱讀:JS魔法堂:函數(shù)節(jié)流(throttle)與函數(shù)去抖(debounce)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/83095.html

相關(guān)文章

  • JS進(jìn)階1---函數(shù)節(jié)流throttle

    摘要:主要實(shí)現(xiàn)思路就是通過(guò)定時(shí)器,通過(guò)設(shè)置延時(shí)時(shí)間,在第一次調(diào)用時(shí),創(chuàng)建定時(shí)器,寫(xiě)入需要執(zhí)行的函數(shù)。如果這時(shí)前一個(gè)定時(shí)器暫未執(zhí)行,則將其替換為新的定時(shí)器。 JS中的函數(shù)節(jié)流 一、什么是函數(shù)節(jié)流(throttle) 概念:限制一個(gè)函數(shù)在一定時(shí)間內(nèi)只能執(zhí)行一次。 舉個(gè)栗子,坐火車(chē)或地鐵,過(guò)安檢的時(shí)候,在一定時(shí)間(例如10秒)內(nèi),只允許一個(gè)乘客通過(guò)安檢入口,以配合安檢人員完成安檢工作。上例中,每1...

    zhou_you 評(píng)論0 收藏0
  • JS進(jìn)階3---函數(shù)節(jié)流” VS “防抖”

    摘要:目的都是為了降低回調(diào)函數(shù)執(zhí)行頻率,節(jié)省計(jì)算機(jī)資源,優(yōu)化性能,提升用戶(hù)體驗(yàn)。函數(shù)防抖事件頻繁觸發(fā)的情況下,只有經(jīng)過(guò)足夠的空閑時(shí)間,才執(zhí)行代碼一次。 函數(shù)節(jié)流和函數(shù)防抖的對(duì)比分析 一、前言 前端開(kāi)發(fā)中,函數(shù)節(jié)流(throttle) 和 函數(shù)防抖(debounce) 作為常用的性能優(yōu)化方法,兩者都是用于優(yōu)化高頻率執(zhí)行 js 代碼的手段,那具體它們有什么異同點(diǎn)呢?有對(duì)這兩個(gè)概念不太了解的小伙伴...

    hlcc 評(píng)論0 收藏0
  • 進(jìn)階 6-3 期】深入淺出節(jié)流函數(shù) throttle

    摘要:引言上一節(jié)我們?cè)敿?xì)聊了聊高階函數(shù)之柯里化,通過(guò)介紹其定義和三種柯里化應(yīng)用,并在最后實(shí)現(xiàn)了一個(gè)通用的函數(shù)。第二種方案來(lái)實(shí)現(xiàn)也存在一個(gè)問(wèn)題,因?yàn)槎〞r(shí)器是延遲執(zhí)行的,所以事件停止觸發(fā)時(shí)必然會(huì)響應(yīng)回調(diào),所以時(shí)無(wú)法生效。 引言 上一節(jié)我們?cè)敿?xì)聊了聊高階函數(shù)之柯里化,通過(guò)介紹其定義和三種柯里化應(yīng)用,并在最后實(shí)現(xiàn)了一個(gè)通用的 currying 函數(shù)。這一小節(jié)會(huì)繼續(xù)之前的篇幅聊聊函數(shù)節(jié)流 thrott...

    baishancloud 評(píng)論0 收藏0
  • Javascript 面試中經(jīng)常被問(wèn)到的三個(gè)問(wèn)題!

    摘要:相反,在討論時(shí),面試中通常會(huì)提到三件事。通過(guò)對(duì)事件對(duì)應(yīng)的回調(diào)函數(shù)進(jìn)行包裹以自由變量的形式緩存時(shí)間信息,最后用來(lái)控制事件的觸發(fā)頻率。而認(rèn)為最后一個(gè)參賽者說(shuō)了算,只要還能吃的,就重新設(shè)定新的定時(shí)器。 showImg(https://segmentfault.com/img/bVboH5x?w=1000&h=750); 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你! 本...

    PrototypeZ 評(píng)論0 收藏0
  • [譯]通過(guò)實(shí)例講解Debouncing和Throtting(防抖與節(jié)流)

    摘要:譯通過(guò)實(shí)例講解和防抖與節(jié)流源碼中推薦的文章,為了學(xué)習(xí)英語(yǔ),翻譯了一下原文鏈接作者本文來(lái)自一位倫敦前端工程師的技術(shù)投稿。首次或立即你可能發(fā)現(xiàn)防抖事件在等待觸發(fā)事件執(zhí)行,直到事件都結(jié)束后它才執(zhí)行。 [譯]通過(guò)實(shí)例講解Debouncing和Throtting(防抖與節(jié)流) lodash源碼中推薦的文章,為了學(xué)習(xí)(英語(yǔ)),翻譯了一下~ 原文鏈接 作者:DAVID CORBACHO 本文來(lái)自一位...

    Jenny_Tong 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<