溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript中函數(shù)節(jié)流的示例分析

發(fā)布時(shí)間:2021-08-11 13:44:57 來源:億速云 閱讀:117 作者:小新 欄目:web開發(fā)

這篇文章給大家分享的是有關(guān)JavaScript中函數(shù)節(jié)流的示例分析的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

JavaScript 函數(shù)節(jié)流詳解

瀏覽器一個(gè)網(wǎng)頁(yè)的UI線程只有一個(gè),他同時(shí)會(huì)處理界面的渲染和頁(yè)面JavaScript代碼的執(zhí)行(簡(jiǎn)單擴(kuò)展一下,瀏覽器或者JavaScript運(yùn)行大環(huán)境并不是單線程,諸如ajax異步回調(diào)、hybrid框架內(nèi)與native通信、事件隊(duì)列、CSS運(yùn)行線程等等都屬于多線程環(huán)境,不過ES6引入了Promise類來減少了部分異步情況)。因此當(dāng)JavaScript代碼運(yùn)行計(jì)算量很大的方法時(shí),就有可能阻塞UI線程,小則導(dǎo)致用戶響應(yīng)卡頓,嚴(yán)重的情況下瀏覽器會(huì)提示頁(yè)面無響應(yīng)是否強(qiáng)制關(guān)閉。例如網(wǎng)頁(yè)的頁(yè)面滾動(dòng)事件、移動(dòng)設(shè)備的滑動(dòng)、縮放事件等。即使沒有出現(xiàn)嚴(yán)重的性能問題,我們也應(yīng)該站在性能優(yōu)化的角度將短時(shí)間內(nèi)會(huì)多次觸發(fā)的大規(guī)模處理時(shí)間進(jìn)行分流計(jì)算。

如何有效避免UI線程運(yùn)行過長(zhǎng)的代碼,是所有用戶交互應(yīng)用需要考慮的問題,同樣的問題在客戶端Android可以使用UI主線程開子線程來分散計(jì)算。與此對(duì)應(yīng)的,js也可以通過引入webWorker來分散計(jì)算,但是在js中有一個(gè)更簡(jiǎn)單并且效果不錯(cuò)的方法:函數(shù)節(jié)流。使用函數(shù)節(jié)流的核心技巧就是使用定時(shí)器分段計(jì)算。具體的實(shí)現(xiàn)方式大致有兩種思路。

·方法一

1.這種實(shí)現(xiàn)方式的思路很好理解:設(shè)置一個(gè)一間隔時(shí)間,比如50毫秒,以此時(shí)間為基準(zhǔn)設(shè)置定時(shí)器,當(dāng)?shù)谝淮斡|發(fā)事件到第二次觸發(fā)事件間隔小于50毫秒時(shí),清除這個(gè)定時(shí)器,并設(shè)置一個(gè)新的定時(shí)器,以此類推,直到有一次事件觸發(fā)后50毫秒內(nèi)沒有重復(fù)觸發(fā)。代碼如下:

function debounce(method){ 
  clearTimeout(method.timer); 
  method.timer=setTimeout(function(){ 
   method(); 
  },50); 
}

這種設(shè)計(jì)方式有一個(gè)問題:本來應(yīng)該多次觸發(fā)的事件,可能最終只會(huì)發(fā)生一次。具體來說,一個(gè)循序漸進(jìn)的滾動(dòng)事件,如果用戶滾動(dòng)太快速,或者程序設(shè)置的函數(shù)節(jié)流間隔時(shí)間太長(zhǎng),那么最終滾動(dòng)事件會(huì)呈現(xiàn)為一個(gè)很突然的跳躍事件,中間過程都被節(jié)流截掉了。這個(gè)例子舉的有點(diǎn)夸張了,不過使用這種方式進(jìn)行節(jié)流最終是會(huì)明顯感受到程序比不節(jié)流的時(shí)候“更突兀”,這對(duì)于用戶體驗(yàn)是很差的。有一種彌補(bǔ)這種缺陷的設(shè)計(jì)思路。

·方法二

2.第二種實(shí)現(xiàn)方式的思路與第一種稍有差別:設(shè)置一個(gè)間隔時(shí)間,比如50毫秒,以此時(shí)間為基準(zhǔn)穩(wěn)定分隔事件觸發(fā)情況,也就是說100毫秒內(nèi)連續(xù)觸發(fā)多次事件,也只會(huì)按照50毫秒一次穩(wěn)定分隔執(zhí)行。代碼如下:

var oldTime=new Date().getTime(); 
var delay=50; 
function throttle1(method){ 
  var curTime=new Date().getTime(); 
  if(curTime-oldTime>=delay){ 
   oldTime=curTime; 
   method(); 
  } 
}

相比于第一種方法,第二種方法也許會(huì)比第一種方法執(zhí)行更多次(有時(shí)候意味著更多次請(qǐng)求后臺(tái),即更多的流量),但是卻很好的解決了第一種方法清除中間過程的缺陷。因此在具體場(chǎng)景應(yīng)根據(jù)情況擇優(yōu)決定使用哪種方法。

對(duì)于方法二,我們?cè)偬峁┝硪环N同樣功能的寫法:

var timer=undefined,delay=50; 
function throttle2(method){ 
  if(timer){ 
    return ; 
  } 
  method(); 
  timer=setTimeout(function(){ 
    timer=undefined; 
  },delay); 
}

最后說點(diǎn)個(gè)外話,說明一下函數(shù)節(jié)流的名稱問題,大家往往會(huì)看到throttle和debounce兩個(gè)方法名,throttle可以譯為“節(jié)制,卡住”,debounce可以譯為“防反跳”。在《JavaScript高級(jí)程序設(shè)計(jì)》中作者介紹了方法一,并且作者使用了“throttle”這個(gè)函數(shù)名。而在《第三方JavaScript編程》書中同時(shí)出現(xiàn)了方法一和方法二,作者將方法一命名為“debounce”,將方法二命名為“throttle”。國(guó)內(nèi)在同時(shí)介紹兩個(gè)方法的時(shí)候有些文章錯(cuò)誤的將方法一命名為“throttle”,而將方法二命名為“debounce”,從英語(yǔ)的角度來說是很不負(fù)責(zé)任的。因此在這里撥亂反正:方法一適合理解為“防反跳”,應(yīng)命名為“debounce”;方法二適合理解為“函數(shù)節(jié)制”,應(yīng)命名為“throttle”。

感謝各位的閱讀!關(guān)于“JavaScript中函數(shù)節(jié)流的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI