細說節流(Throttle)和防抖(Debounce)

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"節流(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Throttle","attrs":{}}],"attrs":{}},{"type":"text","text":")和防抖(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Debounce","attrs":{}}],"attrs":{}},{"type":"text","text":")對於前端開發人員來說應該是十分熟悉的,節流(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Throttle","attrs":{}}],"attrs":{}},{"type":"text","text":")和防抖(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Debounce","attrs":{}}],"attrs":{}},{"type":"text","text":")是兩種可以節省性能的編程技術,兩者的目的都是爲了優化性能,提高用戶體驗,都是基於 DOM 事件限制正在執行的 JavaScript 數量的方法。但兩者的有什麼不一樣呢?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"節流會強制執行一個函數在一段時間內可以被調用的最大次數。如“","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"最多每 100 毫秒執行一次此函數","attrs":{}},{"type":"text","text":"”。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假設在正常情況下,會在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"10","attrs":{}}],"attrs":{}},{"type":"text","text":" 秒內調用此函數 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"1,000","attrs":{}}],"attrs":{}},{"type":"text","text":" 次。如果將其限制爲每 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"100","attrs":{}}],"attrs":{}},{"type":"text","text":" 毫秒僅一次,則該函數最多隻會執行 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"100","attrs":{}}],"attrs":{}},{"type":"text","text":" 次。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"(10s * 1,000)","attrs":{}}],"attrs":{}},{"type":"text","text":" = ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"10,000 ms","attrs":{}}],"attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"10,000 ms / 100 ms","attrs":{}}],"attrs":{}},{"type":"text","text":" 限制 = ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"100","attrs":{}}],"attrs":{}},{"type":"text","text":" 個最大調用","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"防抖強制一個函數在一段時間內沒有被調用之前不會被再次調用。如“","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"僅當 100 毫秒過去了而沒有被調用時才執行此函數","attrs":{}},{"type":"text","text":"”。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"也許一個函數在短時間內被調用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"1000","attrs":{}}],"attrs":{}},{"type":"text","text":" 次,分散在3秒內,然後停止調用。如果在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"100","attrs":{}}],"attrs":{}},{"type":"text","text":" 毫秒的時間內啓動,這個功能只會在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"3.1","attrs":{}}],"attrs":{}},{"type":"text","text":" 秒的時間內啓動一次。每次在突發事件期間調用該函數時,它都會重置恢復計時器。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"區別是什麼?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些概念的一個主要用例是某些 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"DOM","attrs":{}}],"attrs":{}},{"type":"text","text":" 事件,例如滾動和調整大小。例如,如果將滾動處理程序附加到一個元素,並將該元素向下滾動 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"5000","attrs":{}}],"attrs":{}},{"type":"text","text":" 像素,可能會看到 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"100","attrs":{}}],"attrs":{}},{"type":"text","text":" 多個事件被觸發。如果事件處理程序做了大量工作(例如繁重的計算和其他 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"DOM","attrs":{}}],"attrs":{}},{"type":"text","text":" 操作),可能會看到性能問題(卡頓)。如果可以減少執行該處理程序的次數,而不會對經驗造成太大影響,那麼這可能是值得的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"常用的場景如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"等到用戶停止調整窗口大小","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在用戶停止輸入之前不要觸發 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"AJAX","attrs":{}}],"attrs":{}},{"type":"text","text":" 事件","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"監測或者獲取頁面的滾動位置,最多每 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"100ms","attrs":{}}],"attrs":{}},{"type":"text","text":" 響應一次","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在應用中拖動元素時確保良好的性能","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"怎麼做?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"節流(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Throttle","attrs":{}}],"attrs":{}},{"type":"text","text":")和防抖(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Debounce","attrs":{}}],"attrs":{}},{"type":"text","text":")兩個函數都內置到 ","attrs":{}},{"type":"link","attrs":{"href":"https://lodash.com/","title":"","type":null},"content":[{"type":"text","text":"Lodash","attrs":{}}]},{"type":"text","text":" 腳本庫中,無需自己實現。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"節流(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Throttle","attrs":{}}],"attrs":{}},{"type":"text","text":")場景","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"$(\"body\").on(\"scroll\", _.throttle(function() {\n // 處理邏輯\n}, 100));\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"防抖(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Debounce","attrs":{}}],"attrs":{}},{"type":"text","text":")場景","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"實際生活中,如百度搜索,輸入文本後會出現下拉選擇,這個過程一般綁定文本事件 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"keypress","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下圖描述了使用防抖(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Debounce","attrs":{}}],"attrs":{}},{"type":"text","text":")前狀態的性能監控捕獲,每次 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"keypress","attrs":{}}],"attrs":{}},{"type":"text","text":" 引發事件時,它都會觸發搜索引擎請求數據並將結果呈現在屏幕上。事實上,這些結果並沒有被用戶看到,因爲它們已經被最新 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"keypress","attrs":{}}],"attrs":{}},{"type":"text","text":" 事件的後續結果覆蓋了,屏幕上僅呈現最新結果。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b7/b7335e62622e15ebc5ee1b89cc634bda.jpeg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面是使用防抖(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Debounce","attrs":{}}],"attrs":{}},{"type":"text","text":")進行優化後的結果,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d1/d19efdce6c365c3efb579fb2590dc300.jpeg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"正如所看到的,搜索過程和結果呈現只調用一次(當用戶完成輸入時),沒有重複調用不重要的功能,如佈局渲染、內存處理、DOM元素管理。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面是以搜索爲場景,展示 AJAX 的請求情況:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b7/b7ef3e4850fd5f01cf3952d7af2ebf9f.jpeg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還有下面的窗口大小調整場景,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"$(window).on(\"resize\", _.debounce(function() {\n // 處理邏輯\n}, 100));\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在現代瀏覽器中,可以使用 ","attrs":{}},{"type":"link","attrs":{"href":"https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame","title":"","type":null},"content":[{"type":"text","text":"requestAnimationFrame","attrs":{}}]},{"type":"text","text":",告訴瀏覽器——你希望執行一個動畫,並且要求瀏覽器在下次重繪之前調用指定的回調函數更新動畫。該方法需要傳入一個回調函數作爲參數,該回調函數會在瀏覽器下一次重繪之前執行。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"節流(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Throttle","attrs":{}}],"attrs":{}},{"type":"text","text":")和防抖(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Debounce","attrs":{}}],"attrs":{}},{"type":"text","text":")這兩個來自於需要延遲功能的執行,因爲用戶不想進行過多的HTTP請求。如今,這些是提高 Web 性能的重要方法。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章