這段時間去面試了兩家當前比較拽的互聯網公司,回來一總結,廣度略有,深度堪憂。這么看來可能覺得還是好事,最近沒事在掘金上看看,不知不覺的關注的標簽已經有40來個了。
eslint,requirejs,three,Web Components,函數式編程,Visual Studio Code,JSON,TypeScript,vuex,WebAssembly,HTTPS,WebGL,DOM,Canvas,敏捷開發,MVVM,React Native,響應式設計,HTTP,全棧,稀土,電子書,chrome,微信,代碼規范,CSS,正則表達式,Node.js, 前端框架, HTML,設計模式,面試,程序員,算法,架構,Webpack......
bla bla bla......
前端就是苦,前端就是累。代碼大家都能寫,寫出什么樣的代碼,那就是功力。
閑話說的太多了,前端時間自己用vue寫了個相當簡單的web音樂播放器,寫完畢以后一直有幾個問題困擾我。
1.vue如何高可用的組件開發。
2.自己寫的搜索(autoComplete),返回數據不准確,可能返回以前關鍵字查詢的結果。
3. vuex 如何在錯誤的時候不阻止程序的繼續執行。
這里我說的是第二個問題,
我原來的考慮,搜索的時候傳遞關鍵字過去, 返回的時候,除了被搜索到的數據,還包括關鍵字本身。
如果當前的輸入框的值和返回的數據的關鍵字匹配,那么展現,反之丟棄。
這里也有問題,如果關鍵字前后兩次相同,那就會數據填充兩次。比如關鍵字為 a->b->a,第一個a落后於b返回。但至少保證了展現的數據是自己期望的數據。
后來看了一下
百度的搜索,也是每次都發送請求,但是一些前面發送的請求會被取消掉,返回html和腳本
bing的搜索,也是每次都發送請求,沒有取消,返回數據,html和腳本。
搜狗,每次發送請求,沒有取消,返回的是數據+腳本。
但是都一個特點,就是返回的都足夠快,這就有點尷尬了。
回頭再看看自己搜索的問題,才發現問題的是自己的邏輯處理問題
1.當字符為空的時候沒有發請求但是沒有清空數據
2.oninput,focus處理有問題
暈死,一天在掘金看到函數節流和函數防抖,本事想應用到這個及時搜索上面來,可是啊哈,走歪了。
回歸,我們來說說函數節流和函數防抖。
函數節流 & 函數防抖
Throttling enforces a maximum number of times a function can be called over time. As in "execute this function at most once every 100 milliseconds".
Debouncing enforces that a function not be called again until a certain amount of time has passed without it being called. As in "execute this function only if 100 milliseconds have passed without it being called".
函數節流:是確保函數特定的時間內至多執行一次。
函數防抖:是函數在特定的時間內不被再調用后執行。
函數節流underscore的實現(解釋,借用的是JS魔法堂:函數節流(throttle)與函數去抖(debounce))
.throttle = function(func, wait, options) { /* options的默認值 * 表示首次調用返回值方法時,會馬上調用func;否則僅會記錄當前時刻,當第二次調用的時間間隔超過wait時,才調用func。 * options.leading = true; * 表示當調用方法時,未到達wait指定的時間間隔,則啟動計時器延遲調用func函數,若后續在既未達到wait指定的時間間隔和func函數又未被調用的情況下調用返回值方法,則被調用請求將被丟棄。 * options.trailing = true; * 注意:當options.trailing = false時,效果與上面的簡單實現效果相同 */ var context, args, result; var timeout = null; var previous = 0; if (!options) options = {}; var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function() { var now = _.now(); if (!previous && options.leading === false) previous = now; // 計算剩余時間 var remaining = wait - (now - previous); context = this; args = arguments; // 當到達wait指定的時間間隔,則調用func函數 // 精彩之處:按理來說remaining <= 0已經足夠證明已經到達wait的時間間隔,但這里還考慮到假如客戶端修改了系統時間則馬上執行func函數。 if (remaining <= 0 || remaining > wait) { // 由於setTimeout存在最小時間精度問題,因此會存在到達wait的時間間隔,但之前設置的setTimeout操作還沒被執行,因此為保險起見,這里先清理setTimeout操作 if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { // options.trailing=true時,延時執行func函數 timeout = setTimeout(later, remaining); } return result; }; };
函數防抖在underscore的實現,其基本思路,就是內部計時,達到指定時間,就執行,不然啟用延時。
_.debounce = function(func, wait, immediate) { // immediate默認為false var timeout, args, context, timestamp, result; var later = function() { // 當wait指定的時間間隔期間多次調用_.debounce返回的函數,則會不斷更新timestamp的值,導致last < wait && last >= 0一直為true,從而不斷啟動新的計時器延時執行func var last = _.now() - timestamp; if (last < wait && last >= 0) { timeout = setTimeout(later, wait - last); } else { timeout = null; if (!immediate) { result = func.apply(context, args); if (!timeout) context = args = null; } } }; return function() { context = this; args = arguments; timestamp = _.now(); // 第一次調用該方法時,且immediate為true,則調用func函數 var callNow = immediate && !timeout; // 在wait指定的時間間隔內首次調用該方法,則啟動計時器定時調用func函數 if (!timeout) timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); context = args = null; } return result; }; };
那么應用場景:
函數節流(throttle)
1. 頻繁的mousemove/keydown,比如高頻的鼠標移動,游戲射擊類的
2. 搜索聯想(keyup)
3. 進度條(我們可能不需要高頻的更新進度)
4. 拖拽的dragover等
5. 高頻的點擊,抽獎等(哈哈,邪惡)
函數防抖(debounce)
1. scroll/resize事件
2. 文本連續輸入,ajax驗證/關鍵字搜索
參考:
淺談 Underscore.js 中 _.throttle 和 _.debounce 的差異
JS魔法堂:函數節流(throttle)與函數去抖(debounce)