亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 6858 | 回復(fù): 1
打印 上一主題 下一主題

[JavaScript] 淺談 Underscore.js 中 _.throttle 和 _.debounce 的差異 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2014-11-03 11:03 |只看該作者 |倒序瀏覽
本帖最后由 Coding扣釘 于 2014-11-03 13:00 編輯

Underscore.js是一個很精干的庫,壓縮后只有5.2KB。它提供了幾十種函數(shù)式編程的方法,彌補了標準庫的不足,大大方便了JavaScript的編程。

本文僅探討Underscore.js的兩個函數(shù)方法 _.throttle 和 _.debounce 的原理、效果和用途。


通常的函數(shù)(或方法)調(diào)用過程分為三個部分:請求、執(zhí)行和響應(yīng)。(文中“請求”與“調(diào)用”同義,“響應(yīng)”與“返回”同義,為了更好的表述,刻意采用請求和響應(yīng)的說法。)

某些場景下,比如響應(yīng)鼠標移動或者窗口大小調(diào)整的事件,觸發(fā)頻率比較高。若稍處理函數(shù)微復(fù)雜,需要較多的運算執(zhí)行時間,響應(yīng)速度跟不上觸發(fā)頻率,往往會出現(xiàn)延遲,導(dǎo)致假死或者卡頓感。

在運算資源不夠的時候,最直觀的解決辦法就是升級硬件,誠然通過購買更好的硬件可以解決部分問題,但是也需要為此付出高額的成本。特別是客戶端和服務(wù)器模式,要求客戶端統(tǒng)一升級硬件基本不可能。

在資源有限的前提下,處理函數(shù)無法即時響應(yīng)高頻調(diào)用。退而求其次,只響應(yīng)部分請求是否可行呢?某些場景下的密集性請求,具備很強的同質(zhì)和連續(xù)性。比如說,鼠標移動的軌跡參數(shù)。響應(yīng)越及時效果越平滑,但是如果響應(yīng)速度跟不上時,反而會出現(xiàn)卡頓感,如果適當?shù)膩G棄一些請求效果更流暢。

throttle 和 debounce 是解決請求和響應(yīng)速度不匹配問題的兩個方案。二者的差異在于選擇不同的策略。

電梯超時

想象每天上班大廈底下的電梯。把電梯完成一次運送,類比為一次函數(shù)的執(zhí)行和響應(yīng)。假設(shè)電梯有兩種運行策略 `throttle` 和 `debounce` ,超時設(shè)定為15秒,不考慮容量限制。

* `throttle` 策略的電梯。保證如果電梯第一個人進來后,15秒后準時運送一次,不等待。如果沒有人,則待機。
* `debounce` 策略的電梯。如果電梯里有人進來,等待15秒。如果又人進來,15秒等待重新計時,直到15秒超時,開始運送。

使用示例

_.throttle 使用示例
  1. javascript
  2. function log( event ) {
  3.   console.log( $(window).scrollTop(), event.timeStamp );
  4. };

  5. // 控制臺記錄窗口滾動事件,觸發(fā)頻率比你想象的要快
  6. $(window).scroll( log );

  7. // 控制臺記錄窗口滾動事件,每250ms最多觸發(fā)一次
  8. $(window).scroll( _.throttle( log, 250 ) );
復(fù)制代碼
_.debounce 使用示例
  1. javascript
  2. function ajax_lookup( event ) {
  3.   // 對輸入的內(nèi)容$(this).val()執(zhí)行 Ajax 查詢
  4. };

  5. // 字符輸入的頻率比你預(yù)想的要快,Ajax 請求來不及回復(fù)。
  6. $('input:text').keyup( ajax_lookup );

  7. // 當用戶停頓250毫秒以后才開始查找
  8. $('input:text').keyup( _.debounce( ajax_lookup. 250 ) );
復(fù)制代碼
underscore源碼注解

讓我們來讀讀源碼,探其究竟;陂_發(fā)版本(1.7.0)的源碼,加上了一些注釋以幫助理解。

_.throttle方法源碼
  1. javascript
  2. /**
  3. * 頻率控制 返回函數(shù)連續(xù)調(diào)用時,func 執(zhí)行頻率限定為 次 / wait
  4. *
  5. * @param  {function}   func      傳入函數(shù)
  6. * @param  {number}     wait      表示時間窗口的間隔
  7. * @param  {object}     options   如果想忽略開始邊界上的調(diào)用,傳入{leading: false}。
  8. *                                如果想忽略結(jié)尾邊界上的調(diào)用,傳入{trailing: false}
  9. * @return {function}             返回客戶調(diào)用函數(shù)   
  10. */
  11. _.throttle = function(func, wait, options) {
  12.   var context, args, result;
  13.   var timeout = null;
  14.   // 上次執(zhí)行時間點
  15.   var previous = 0;
  16.   if (!options) options = {};
  17.   // 延遲執(zhí)行函數(shù)
  18.   var later = function() {
  19.     // 若設(shè)定了開始邊界不執(zhí)行選項,上次執(zhí)行時間始終為0
  20.     previous = options.leading === false ? 0 : _.now();
  21.     timeout = null;
  22.     result = func.apply(context, args);
  23.     if (!timeout) context = args = null;
  24.   };
  25.   return function() {
  26.     var now = _.now();
  27.     // 首次執(zhí)行時,如果設(shè)定了開始邊界不執(zhí)行選項,將上次執(zhí)行時間設(shè)定為當前時間。
  28.     if (!previous && options.leading === false) previous = now;
  29.     // 延遲執(zhí)行時間間隔
  30.     var remaining = wait - (now - previous);
  31.     context = this;
  32.     args = arguments;
  33.     // 延遲時間間隔remaining小于等于0,表示上次執(zhí)行至此所間隔時間已經(jīng)超過一個時間窗口
  34.     // remaining大于時間窗口wait,表示客戶端系統(tǒng)時間被調(diào)整過
  35.     if (remaining <= 0 || remaining > wait) {
  36.       clearTimeout(timeout);
  37.       timeout = null;
  38.       previous = now;
  39.       result = func.apply(context, args);
  40.       if (!timeout) context = args = null;
  41.     //如果延遲執(zhí)行不存在,且沒有設(shè)定結(jié)尾邊界不執(zhí)行選項
  42.     } else if (!timeout && options.trailing !== false) {
  43.       timeout = setTimeout(later, remaining);
  44.     }
  45.     return result;
  46.   };
  47. };
復(fù)制代碼
_.debounce方法源碼
  1. javascript
  2. /**
  3. * 空閑控制 返回函數(shù)連續(xù)調(diào)用時,空閑時間必須大于或等于 wait,func 才會執(zhí)行
  4. *
  5. * @param  {function} func        傳入函數(shù)
  6. * @param  {number}   wait        表示時間窗口的間隔
  7. * @param  {boolean}  immediate   設(shè)置為ture時,調(diào)用觸發(fā)于開始邊界而不是結(jié)束邊界
  8. * @return {function}             返回客戶調(diào)用函數(shù)
  9. */
  10. _.debounce = function(func, wait, immediate) {
  11.   var timeout, args, context, timestamp, result;

  12.   var later = function() {
  13.     // 據(jù)上一次觸發(fā)時間間隔
  14.     var last = _.now() - timestamp;

  15.     // 上次被包裝函數(shù)被調(diào)用時間間隔last小于設(shè)定時間間隔wait
  16.     if (last < wait && last > 0) {
  17.       timeout = setTimeout(later, wait - last);
  18.     } else {
  19.       timeout = null;
  20.       // 如果設(shè)定為immediate===true,因為開始邊界已經(jīng)調(diào)用過了此處無需調(diào)用
  21.       if (!immediate) {
  22.         result = func.apply(context, args);
  23.         if (!timeout) context = args = null;
  24.       }
  25.     }
  26.   };

  27.   return function() {
  28.     context = this;
  29.     args = arguments;
  30.     timestamp = _.now();
  31.     var callNow = immediate && !timeout;
  32.     // 如果延時不存在,重新設(shè)定延時
  33.     if (!timeout) timeout = setTimeout(later, wait);
  34.     if (callNow) {
  35.       result = func.apply(context, args);
  36.       context = args = null;
  37.     }

  38.     return result;
  39.   };
  40. };
復(fù)制代碼
可視化演示

提示: 由于一些因素,圖片上傳失敗,點擊此處移步到原文鏈接,謝謝。

示例中每一行都以30ms的速度繪制時間軸,第一行Mousemove Events是參考基準,以50ms每次的響應(yīng)頻率,在時間軸上輸出循環(huán)可見ASCII碼字符。

當鼠標進入左側(cè)方型區(qū)域(mouseenter 事件)所有行開始繪制時間軸, 鼠標晃動(mousemove 事件)會在時間軸上繪制字符塊,每個字符塊表示事件被觸發(fā)一次。為了展現(xiàn)延遲觸發(fā)效果,相鄰字符塊的演示和文字是不同的。

頂部的兩個按鈕`每100毫秒觸發(fā)1次`和`每200毫秒觸發(fā)2次`演示以固定頻率勻速觸發(fā)事件的效果。

演示地址:http://throttle-debounce.coding.io/
源碼地址:https://coding.net/u/duwan/p/throttle-debounce/

使用場景

只要牽涉到連續(xù)事件或頻率控制相關(guān)的應(yīng)用都可以考慮到這兩個函數(shù),比如:

游戲射擊,keydown 事件
文本輸入、自動完成,keyup 事件
鼠標移動,mousemove 事件
DOM 元素動態(tài)定位,window 對象的 resize 和 scroll 事件

前兩者 debounce 和 throttle 都可以按需使用;后兩者肯定是用 throttle 了。如果不做過濾處理,每秒種甚至?xí)|發(fā)數(shù)十次相應(yīng)的事件。尤其是 mousemove 事件,每移動一像素都可能觸發(fā)一次事件。如果是在一個畫布上做一個鼠標相關(guān)的應(yīng)用,過濾事件處理是必須的,否則肯定會造成糟糕的體驗。

參考閱讀
1. [UNDERSCORE.JS]
2. 高階函數(shù) debounce 和 throttle
3. jQuery throttle / debounce: Sometimes, less is more!
4. Debounce and Throttle: a visual explanation



Vangie Du
將來的你,一定會感謝現(xiàn)在拼命努力的自己!
技術(shù)博客: blog.coding.net

論壇徽章:
0
2 [報告]
發(fā)表于 2014-12-02 22:49 |只看該作者
無非,一個是每隔幾秒執(zhí)行,另一個是你放手才執(zhí)行
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP