JavaScript 函數節(jié)流詳解及方法總結
JavaScript 函數節(jié)流詳解
瀏覽器一個網頁的UI線程只有一個,他同時會處理界面的渲染和頁面JavaScript代碼的執(zhí)行(簡單擴展一下,瀏覽器或者JavaScript運行大環(huán)境并不是單線程,諸如ajax異步回調、hybrid框架內與native通信、事件隊列、CSS運行線程等等都屬于多線程環(huán)境,不過ES6引入了Promise類來減少了部分異步情況)。因此當JavaScript代碼運行計算量很大的方法時,就有可能阻塞UI線程,小則導致用戶響應卡頓,嚴重的情況下瀏覽器會提示頁面無響應是否強制關閉。例如網頁的頁面滾動事件、移動設備的滑動、縮放事件等。即使沒有出現嚴重的性能問題,我們也應該站在性能優(yōu)化的角度將短時間內會多次觸發(fā)的大規(guī)模處理時間進行分流計算。
如何有效避免UI線程運行過長的代碼,是所有用戶交互應用需要考慮的問題,同樣的問題在客戶端Android可以使用UI主線程開子線程來分散計算。與此對應的,js也可以通過引入webWorker來分散計算,但是在js中有一個更簡單并且效果不錯的方法:函數節(jié)流。使用函數節(jié)流的核心技巧就是使用定時器分段計算。具體的實現方式大致有兩種思路。
·方法一
1.這種實現方式的思路很好理解:設置一個一間隔時間,比如50毫秒,以此時間為基準設置定時器,當第一次觸發(fā)事件到第二次觸發(fā)事件間隔小于50毫秒時,清除這個定時器,并設置一個新的定時器,以此類推,直到有一次事件觸發(fā)后50毫秒內沒有重復觸發(fā)。代碼如下:
function debounce(method){
clearTimeout(method.timer);
method.timer=setTimeout(function(){
method();
},50);
}
這種設計方式有一個問題:本來應該多次觸發(fā)的事件,可能最終只會發(fā)生一次。具體來說,一個循序漸進的滾動事件,如果用戶滾動太快速,或者程序設置的函數節(jié)流間隔時間太長,那么最終滾動事件會呈現為一個很突然的跳躍事件,中間過程都被節(jié)流截掉了。這個例子舉的有點夸張了,不過使用這種方式進行節(jié)流最終是會明顯感受到程序比不節(jié)流的時候“更突兀”,這對于用戶體驗是很差的。有一種彌補這種缺陷的設計思路。
·方法二
2.第二種實現方式的思路與第一種稍有差別:設置一個間隔時間,比如50毫秒,以此時間為基準穩(wěn)定分隔事件觸發(fā)情況,也就是說100毫秒內連續(xù)觸發(fā)多次事件,也只會按照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();
}
}
相比于第一種方法,第二種方法也許會比第一種方法執(zhí)行更多次(有時候意味著更多次請求后臺,即更多的流量),但是卻很好的解決了第一種方法清除中間過程的缺陷。因此在具體場景應根據情況擇優(yōu)決定使用哪種方法。
對于方法二,我們再提供另一種同樣功能的寫法:
var timer=undefined,delay=50;
function throttle2(method){
if(timer){
return ;
}
method();
timer=setTimeout(function(){
timer=undefined;
},delay);
}
最后說點個外話,說明一下函數節(jié)流的名稱問題,大家往往會看到throttle和debounce兩個方法名,throttle可以譯為“節(jié)制,卡住”,debounce可以譯為“防反跳”。在《JavaScript高級程序設計》中作者介紹了方法一,并且作者使用了“throttle”這個函數名。而在《第三方JavaScript編程》書中同時出現了方法一和方法二,作者將方法一命名為“debounce”,將方法二命名為“throttle”。國內在同時介紹兩個方法的時候有些文章錯誤的將方法一命名為“throttle”,而將方法二命名為“debounce”,從英語的角度來說是很不負責任的。因此在這里撥亂反正:方法一適合理解為“防反跳”,應命名為“debounce”;方法二適合理解為“函數節(jié)制”,應命名為“throttle”。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關文章
關于UTF-8的客戶端用AJAX方式獲取GB2312的服務器端亂碼問題的解決辦法
客戶端是UTF-8編碼,這也是現在大家公認的標準編碼在這種情況下,實用AJAX異步獲取GB2312編碼的服務器端信息時,不可避免的要遇到漢字亂碼問題2010-11-11
bootstrap fileinput組件整合Springmvc上傳圖片到本地磁盤
這篇文章主要介紹了bootstrap fileinput組件整合Springmvc上傳圖片到本地磁盤的方法,需要的朋友可以參考下2017-05-05

