2019 面試準備 - JS 防抖與節流

Create by jsliang on 2019-2-23 20:55:34
Recently revised in 2019-3-12 21:34:59javascript

Hello 小夥伴們,若是以爲本文還不錯,記得給個 star , 大家的 star 是我學習的動力!GitHub 地址php


【2019-08-16】Hello 小夥伴們,因爲 jsliang 對文檔庫進行了重構,這篇文章的一些連接可能失效,而 jsliang 沒有精力維護掘金這邊的舊文章,對此深感抱歉。請須要獲取最新文章的小夥伴,點擊上面的 GitHub 地址,去文檔庫查看調整後的文章。html


本文涉及知識點前端

  • 防抖與節流
  • 重繪與迴流
  • 瀏覽器解析 URL
  • DNS 域名解析
  • TCP 三次握手與四次揮手
  • 瀏覽器渲染頁面

在本文中,jsliang 會講解經過自我探索後關於上述知識點的我的理解,若有紕漏、疏忽或者誤解,歡迎各位小夥伴留言指出。java

若是小夥伴對文章存有疑問,想快速獲得回覆。
或者小夥伴對 jsliang 我的的前端文檔庫感興趣,也想將本身的前端知識整理出來。
歡迎加 QQ 羣一塊兒探討:798961601git

一 目錄

不折騰的前端,和鹹魚有什麼區別github

目錄
一 目錄
二 前言
三 防抖與節流
3.1 防抖
3.2 節流
四 重繪與迴流
五 瀏覽器解析 URL
六 DNS 域名解析
七 TCP 三次握手與四次揮手
八 瀏覽器渲染頁面
九 總結
十 參考文獻

二 前言

返回目錄面試

在工做中,咱們可能碰到這樣的問題:數據庫

  • 用戶在搜索的時候,在不停敲字,若是每敲一個字咱們就要調一次接口,接口調用太頻繁,給卡住了。
  • 用戶在閱讀文章的時候,咱們須要監聽用戶滾動到了哪一個標題,可是每滾動一下就監聽,那樣會太過頻繁從而佔內存,若是再加上其餘的業務代碼,就卡住了。

因此,這時候,咱們就要用到 防抖與節流 了。後端

那麼,講到 防抖與節流,咱們能夠順帶探祕下 重繪與迴流

提及 重繪與迴流,咱們就順帶把 瀏覽器輸入 URL 後發生的事情 也關注一下,從而引出 DNSTCP 等知識點,最終串起來構成本文的輪廓,方便 jsliang 和小夥伴們對這塊知識的整理與記憶。

三 防抖與節流

返回目錄

經過代碼去了解某樣事物,每每是瞭解某個知識點最快的形式。

3.1 防抖

返回目錄

下面咱們有段防抖小案例代碼。

若是小夥伴們手頭有電腦,並感興趣想先本身思考下什麼是防抖。能夠將代碼複製到瀏覽器,嘗試點擊按鈕,並關注下控制檯,看看 Console 是如何打印的。

若是小夥伴們手頭沒有電腦,那麼咱一塊兒先瞅瞅代碼實現,再看看下面 GIF 演示。(這樣效果沒有本身敲的直白有效)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>防抖</title>
</head>
<body>
  <button id="debounce">點我防抖!</button>

  <script> window.onload = function() { // 一、獲取這個按鈕,並綁定事件 var myDebounce = document.getElementById("debounce"); myDebounce.addEventListener("click", debounce(sayDebounce)); } // 二、防抖功能函數,接受傳參 function debounce(fn) { // 四、建立一個標記用來存放定時器的返回值 let timeout = null; return function() { // 五、每次當用戶點擊/輸入的時候,把前一個定時器清除 clearTimeout(timeout); // 六、而後建立一個新的 setTimeout, // 這樣就能保證點擊按鈕後的 interval 間隔內 // 若是用戶還點擊了的話,就不會執行 fn 函數 timeout = setTimeout(() => { fn.call(this, arguments); }, 1000); }; } // 三、須要進行防抖的事件處理 function sayDebounce() { // ... 有些須要防抖的工做,在這裏執行 console.log("防抖成功!"); } </script>
</body>
</html>
複製代碼

很好,相信小夥伴們已經看完了代碼,下面咱們看看它的演示:

這時候,咱們能夠拋出防抖的概念了:

  • 防抖任務頻繁觸發的狀況下,只有任務觸發的間隔超過指定間隔的時候,任務纔會執行。

結合上面的代碼,咱們能夠了解到,在觸發點擊事件後,若是用戶再次點擊了,咱們會清空以前的定時器,從新生成一個定時器。意思就是:這件事兒須要等待,若是你反覆催促,我就從新計時!

空講無益,show you 場景:

  • 有個輸入框,輸入以後會調用接口,獲取聯想詞。可是,由於頻繁調用接口不太好,因此咱們在代碼中使用防抖功能,只有在用戶輸入完畢的一段時間後,纔會調用接口,出現聯想詞。

小夥伴們能夠嘗試看着上面的案例,先本身實現一遍這個場景的解決,若是感受不行,那就看:《防抖和節流的應用場景和實現》

知識點補充:何爲 arguments
首先,後端轉前端的同窗,能夠將 arguments 理解爲能實現重載函數功能的工具。
而後,咱們舉個例子:在 function test() 這個方法中,因爲咱們不肯定變量有多少,好比 test("jsliang", 24),又或者 test("LiangJunrong", "jsliang", "24"),這時候只須要在函數 test 中用 arguments 接收就好了。
最後,在 function test() { let arr1 = argument[0] } 中,arr1 就能夠獲取到傳進來的第一個變量。
因此fn.call(this, arguments) 實際上是將不肯定變量替換到函數中了。

參考資料 1:《閒聊 JS 中的 apply 和 call》
參考資料 2:《js 中 arguments 的用法》

3.2 節流

返回目錄

說完防抖,下面咱們講講節流,規矩就不說了,先上代碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>節流</title>
</head>
<body>

  <button id="throttle">點我節流!</button>

  <script> window.onload = function() { // 一、獲取按鈕,綁定點擊事件 var myThrottle = document.getElementById("throttle"); myThrottle.addEventListener("click", throttle(sayThrottle)); } // 二、節流函數體 function throttle(fn) { // 四、經過閉包保存一個標記 let canRun = true; return function() { // 五、在函數開頭判斷標誌是否爲 true,不爲 true 則中斷函數 if(!canRun) { return; } // 六、將 canRun 設置爲 false,防止執行以前再被執行 canRun = false; // 七、定時器 setTimeout( () => { fn.call(this, arguments); // 八、執行完事件(好比調用完接口)以後,從新將這個標誌設置爲 true canRun = true; }, 1000); }; } // 三、須要節流的事件 function sayThrottle() { console.log("節流成功!"); } </script>
</body>
</html>
複製代碼

很好,看完代碼的小夥伴應該大體清楚是怎麼回事了,下面咱們看 GIF 實現:

看完代碼和 GIF 實現,咱們能夠明白,節流便是:

  • 節流指定時間間隔內只會執行一次任務。

那麼,節流在工做中的應用?

  1. 懶加載要監聽計算滾動條的位置,使用節流按必定時間的頻率獲取。
  2. 用戶點擊提交按鈕,假設咱們知道接口大體的返回時間的狀況下,咱們使用節流,只容許必定時間內點擊一次。

這樣,在某些特定的工做場景,咱們就可使用防抖與節流來減小沒必要要的損耗。

那麼問題來了,假設面試官聽到你這句話,是否是會接着問一句:「爲何說上面的場景不節制會形成過多損耗呢?」

OK,這就涉及到瀏覽器渲染頁面的機制了……

四 重繪與迴流

返回目錄

在說瀏覽器渲染頁面以前,咱們須要先了解兩個點,一個叫 瀏覽器解析 URL,另外一個就是本章節將涉及的 重繪與迴流

  • 重繪(repaint):當元素樣式的改變不影響佈局時,瀏覽器將使用重繪對元素進行更新,此時因爲只須要 UI 層面的從新像素繪製,所以損耗較少

常見的重繪操做有:

  1. 改變元素顏色
  2. 改變元素背景色
  3. more ……
  • 迴流(reflow):又叫重排(layout)。當元素的尺寸、結構或者觸發某些屬性時,瀏覽器會從新渲染頁面,稱爲迴流。此時,瀏覽器須要從新通過計算,計算後還須要從新頁面佈局,所以是較重的操做。

常見的迴流操做有:

  1. 頁面初次渲染
  2. 瀏覽器窗口大小改變
  3. 元素尺寸/位置/內容發生改變
  4. 元素字體大小變化
  5. 添加或者刪除可見的 DOM 元素
  6. 激活 CSS 僞類(:hover……)
  7. more ……
  • 重點迴流一定會觸發重繪,重繪不必定會觸發迴流。重繪的開銷較小,迴流的代價較高。

看到這裏,小夥伴們可能有點懵逼,你剛剛還跟我講着 防抖與節流 ,怎麼一會兒跳到 重繪與迴流 了?

OK,賣個關子,先看下面場景:

  • 界面上有個 div 框,用戶能夠在 input 框中輸入 div 框的一些信息,例如寬、高等,輸入完畢當即改變屬性。可是,由於改變以後還要隨時存儲到數據庫中,因此須要調用接口。若是不加限制……

看到這裏,小夥伴們能夠將一些字眼結合起來了:爲何須要 節流,由於有些事情會形成瀏覽器的 迴流,而 迴流 會使瀏覽器開銷增大,因此咱們經過 節流 來防止這種增大瀏覽器開銷的事情。

形象地用圖來講明:

這樣,咱們就能夠形象的將 防抖與節流重繪與迴流 結合起來記憶起來。

那麼,在工做中咱們要如何避免大量使用重繪與迴流呢?:

  1. 避免頻繁操做樣式,可彙總後統一一次修改
  2. 儘可能使用 class 進行樣式修改,而不是直接操做樣式
  3. 減小 DOM 的操做,可以使用字符串一次性插入

OK,至此咱們就講完兩個部分了,那麼問題又來了:「瀏覽器渲染過程當中,是否是也有重繪與迴流?」「從瀏覽器輸入 URL 到渲染成功的過程當中,究竟發生了什麼?」

咱們,繼續深刻探索……

五 瀏覽器解析 URL

返回目錄

爲了能讓咱們的知識層面看起來更有深度,咱們應該考慮下面兩個問題了:

  • 從瀏覽器輸入 URL 到渲染成功的過程當中,究竟發生了什麼?
  • 瀏覽器渲染過程當中,發生了什麼,是否是也有重繪與迴流?

OK,興致來了,咱們就先從 瀏覽器解析 URL 看起,先來看看當用戶輸入 URL,到瀏覽器呈現給用戶頁面,經歷瞭如下過程:

  • 版本 A
  1. 用戶輸入 URL 地址。
  2. 對 URL 地址進行 DNS 域名解析。
  3. 創建 TCP 鏈接(三次握手)。
  4. 瀏覽器發起 HTTP 請求報文。
  5. 服務器返回 HTTP 響應報文。
  6. 關閉 TCP 鏈接(四次揮手)。
  7. 瀏覽器解析文檔資源並渲染頁面。

講到這裏,忽然想起一個對話:

學生:「老師,這門課的考試重點是什麼?」

老師:「全都是重點!」

enm...老師會不會被打我不知道,可是 jsliang 這樣寫會被懟我就清楚,因此,咱仍是結合上面的圖,進一步勾勒咱們的結構:

很好,jsliang 感受本身的畫圖技術又進了一步~

①:雖然很感激網上有那麼多的文章能夠參考,可是在我查了二十來篇文章後,jsliang 以爲這部分十有八九有問題撒,問了些小夥伴,它們有的說對,有的說錯。不過,不妨礙小夥伴們繼續往下看哈。
②:爲了不出簍子,下面貼出另一個版本,小夥伴們能夠在評論區說出你支持哪一個版本哈:

  • 版本 B
  1. 用戶輸入 URL 地址。
  2. 對 URL 地址進行 DNS 域名解析。
  3. 進行 TCP 鏈接。
  4. 進行 HTTP 報文的請求與響應。
  5. 瀏覽器解析文檔資源並渲染頁面。

在這裏咱們能夠清晰的瞭解到從 用戶輸入 URL,到瀏覽器呈現給用戶頁面,經歷了哪些過程

那麼剩下的就簡單了:

  1. 什麼是 DNS 解析,它是怎麼個流程?
  2. 什麼是 TCP 三次握手,什麼是 TCP 四次揮手,它們的流程是怎樣的?
  3. 瀏覽器解析文檔資源並渲染頁面是個怎樣的流程?

Let's go~ 逐步完成下面三個知識點!

參考文獻 1:《網頁解析的全過程(輸入url到展現頁面)》
參考文獻 2:《瀏覽器渲染頁面過程剖析》

六 DNS 域名解析

返回目錄

首先,咱們解決第一個問題:

  • 什麼是 DNS 解析,它是怎麼個流程?

DNS(Domain Name System)是 域名系統 的英文縮寫,提供的服務是用於將主機名和域名轉換爲 IP 地址的工做:

域名:http://jsliang.top <---> DNS <---> IPV4:119.147.15.13

IPV4 是造假的,僅用來講明 DNS 解析後能返回 IP 地址

因此,當用戶在瀏覽器輸入 http://jsliang.top 時,DNS 經歷瞭如下步驟:

  1. 瀏覽器根據地址,在自身緩存中查找 DNS(域名服務器) 中的解析記錄。若是存在,則直接返回 IP 地址;若是不存在,則查找操做系統中的 hosts 文件是否有該域名的 DNS 解析記錄,若是有就返回。
  2. 在條件 1 中的瀏覽器緩存或者操做系統的 hosts 文件中都沒有這個域名的 DNS 解析記錄,或者已通過期,則向域名服務器發起請求解析這個域名。
  3. 先向本地域名服務器中請求,讓它解析這個域名,若是解析不了,則向根域名服務器請求解析。
  4. 根服務器給本地域名服務器返回一個主域名服務器。
  5. 本地域名服務器向主域名服務器發起解析請求。
  6. 主域名服務器接收到解析請求後,查找並返回域名對應的域名服務器的地址。
  7. 域名服務器會查詢存儲的域名和 IP 的映射關係表,返回目標 IP 記錄以及一個 TTL(Time To Live)值。
  8. 本地域名服務器接收到 IP 和 TTL 值,進行緩存,緩存的時間由 TTL 值控制。
  9. 將解析的結果返回給用戶,用戶根據 TTL 值緩存在本地系統緩存中,域名解析過程結束。

看文字老是難以理解的,跟着 jsliang 畫張圖過一遍,就感受清晰了:

七 TCP 三次握手與四次揮手

返回目錄

而後,咱們解決第二個問題:

  • 什麼是 TCP 三次握手,什麼是 TCP 四次揮手,它們的流程是怎樣的?

什麼是 TCP 呢?TCP(Transmission Control Protocol 傳輸控制協議)是一種面向鏈接的、可靠的、基於字節流的傳輸層通訊協議。

簡單來講,它的做用就是將數據流從一臺主機可靠地傳輸到另外一臺主機。

至於具體的工做原理,這裏暫時涉及不到,咱們目前只想知道兩個點:三次握手與四次揮手

  • 三次握手
  1. 第一次握手:起初兩端都處於 CLOSED 關閉狀態,Client 將標誌位 SYN 置爲 1,隨機產生一個值 seq = x,並將該數據包發送給 Server,Client 進入 SYN-SENT 狀態,等待 Server 確認。
  2. 第二次握手:Server 收到數據包後由標誌位 SYN = 1 得知 Client 請求創建鏈接,Server 將標誌位 SYN 和 ACK 都置爲 1,ack = x + 1,隨機產生一個值 seq = y,並將該數據包發送給Client以確認鏈接請求,Server 進入 SYN-RCVD 狀態,此時操做系統爲該 TCP 鏈接分配 TCP 緩存和變量。
  3. 第三次握手:Client 收到確認後,檢查 seq 是否爲 x + 1,ACK 是否爲 1,若是正確則將標誌位 ACK 置爲 1,ack = y + 1,而且此時操做系統爲該 TCP 鏈接分配 TCP 緩存和變量,並將該數據包發送給 Server,Server 檢查 ack 是否爲 y + 1,ACK 是否爲 1,若是正確則鏈接創建成功,Client 和 Server 進入 established 狀態,完成三次握手,隨後 Client 和 Server 就能夠開始傳輸數據。

文字太亂,show you picture:

  • 四次揮手
  1. 第一次揮手:Client 的應用進程先向其 TCP 發出鏈接釋放報文段(FIN = 1,序號 seq = u),並中止再發送數據,主動關閉 TCP 鏈接,進入 FIN-WAIT-1(終止等待1)狀態,等待 Server 的確認。
  2. 第二次揮手:Server 收到鏈接釋放報文段後即發出確認報文段,(ACK = 1,確認號 ack = u + 1,序號 seq = v),Server 進入 CLOSE-WAIT(關閉等待)狀態,此時的 TCP 處於半關閉狀態,Client 到 Server 的鏈接釋放。

注:Client 收到 Server 的確認後,進入 FIN-WAIT-2(終止等待2)狀態,等待 Server 發出的鏈接釋放報文段。

  1. 第三次揮手:Server 已經沒有要向 Client 發出的數據了,Server 發出鏈接釋放報文段(FIN = 1ACK = 1,序號 seq = w,確認號 ack = u + 1),Server 進入 LAST-ACK(最後確認)狀態,等待 Client 的確認。
  2. 第四次揮手:Client 收到 Server 的鏈接釋放報文段後,對此發出確認報文段(ACK = 1seq = u + 1ack = w + 1),Client 進入 TIME-WAIT(時間等待)狀態。此時 TCP 未釋放掉,須要通過時間等待計時器設置的時間 2MSL 後,Client 才進入 CLOSED 狀態。

文字太亂,show you picture:

OK,至此咱們就理解了 TCP 及其三次握手和四次揮手過程,爲了方便小夥伴們形象記憶,jsliang 搞了個小故事,但願小夥伴們能加深印象:

  • 三次握手 + 四次揮手形象記憶
  1. jsliang:(對妹子發起微信好友申請)「你好,我能夠加你好友嗎?」 —— 第一次握手
  2. 妹子:(經過審覈)「你好,很高興認識你~」 —— 第二次握手
  3. jsliang:「你好,我叫梁峻榮,前端折騰小能手……」 —— 第三次握手
  4. ……(聊天內容)
  5. …………(聊天內容)
  6. ………………(聊天內容)
  7. …………(聊天內容)
  8. ……(聊天內容)
  9. jsliang:(感冒拍了張紙簍都是紙巾的圖)「啊,好難受今天。」 —— 第一次揮手
  10. 妹子:「臥槽,你好惡心!」 —— 第二次揮手
  11. 妹子:「咱仍是當不認識吧,互刪了,謝謝!」 —— 第三次揮手
  12. jsliang:(呆)「不是,你聽我說!」 —— 第四次揮手
  13. 妹子:(果斷刪除好友) —— CLOSED
  14. jsliang:(!「我今天感冒了。」 妹子開啓了好友驗證,你還不是她好友。請先發送好友驗證請求,對方驗證經過後,才能聊天。) ——— CLOSED

OK,成功出糗,相信小夥伴們有了個很好的瞭解了。

那麼,咱們繼續前行探索。

參考文獻 1:《TCP三次握手和四次揮手過程》
參考文獻 2:《TCP的三次握手與四次揮手(詳解+動圖)》

八 瀏覽器渲染頁面

返回目錄

最後,咱們解決第三個問題:

  • 瀏覽器解析文檔資源並渲染頁面是個怎樣的流程?

話很少說,一塊兒來看:

  1. 瀏覽器經過 HTMLParser 根據深度遍歷的原則把 HTML 解析成 DOM Tree。
  2. 瀏覽器經過 CSSParser 將 CSS 解析成 CSS Rule Tree(CSSOM Tree)。
  3. 瀏覽器將 JavaScript 經過 DOM API 或者 CSSOM API 將 JS 代碼解析並應用到佈局中,按要求呈現響應的結果。
  4. 根據 DOM 樹和 CSSOM 樹來構造 render Tree。
  5. layout:重排(也能夠叫回流),當 render tree 中任一節點的幾何尺寸發生改變,render tree 就會從新佈局,從新來計算全部節點在屏幕的位置。
  6. repaint:重繪,當 render tree 中任一元素樣式屬性(幾何尺寸沒改變)發生改變時,render tree 都會從新畫,好比字體顏色,背景等變化。
  7. paint:遍歷 render tree,並調動硬件圖形 API 來繪製每一個節點。

文字講解確定仍是不夠清晰的,可是 jsliang 畫了幾張圖也累了,因此我們 來了一張圖:

這樣,咱們就對 瀏覽器渲染頁面過程 一清二楚啦~

參考文獻:《一篇文章搞定前端面試》

九 總結

返回目錄

至此,咱們回顧下本身作了什麼?

  1. 咱們在工做中碰到一些問題,這些問題會卡住頁面,因而咱們查資料,知道想要減小瀏覽器的開銷,咱們就須要使用 防抖與節流
  2. 使用 防抖與節流 解決完問題後,咱們好奇爲何會有這樣的操做,因而咱們深刻了解了下 重繪與迴流
  3. 重繪與迴流 只告訴了咱們瀏覽器在 CSS 上的渲染,咱們須要進一步瞭解 瀏覽器渲染頁面 的詳細過程,但洋蔥仍是要一層一層剝開的,因此咱們須要從 瀏覽器解析 URL 開始瞭解。
  4. 瀏覽器解析 URL 中,咱們順帶了解下 DNS 域名解析TCP 三次握手與四次揮手 這兩個知識點。
  5. 最後,咱們終於知道了 瀏覽器渲染頁面 是怎麼一回事。

綜上,若是咱們僅僅是須要關注面試的一個點,咱們極可能由於不知頭尾,而被面試官問得啞口無言。

可是,若是咱們知道一個知識點,並對其進行思路發散,深刻學習,相信面試官問起來的時候,小夥伴們就能夠侃侃而談,而不會被問地體無完膚了!

最後祝小夥伴們找到合適的滿意的工做~

十 參考文獻

返回目錄

  1. 《函數防抖和節流》
  2. 《節流 & 防抖》
  3. 《JS奇淫巧技:防抖函數與節流函數》
  4. 《閒聊 JS 中的 apply 和 call》
  5. 《js 中 arguments 的用法》
  6. 《防抖和節流的應用場景和實現》
  7. 《網頁解析的全過程(輸入url到展現頁面)》
  8. 《瀏覽器渲染頁面過程剖析》
  9. 《一篇文章搞定前端面試》

jsliang 廣告推送:
也許小夥伴想了解下雲服務器
或者小夥伴想買一臺雲服務器
或者小夥伴須要續費雲服務器
歡迎點擊 雲服務器推廣 查看!

知識共享許可協議
jsliang 的文檔庫梁峻榮 採用 知識共享 署名-非商業性使用-相同方式共享 4.0 國際 許可協議進行許可。
基於github.com/LiangJunron…上的做品創做。
本許可協議受權以外的使用權限能夠從 creativecommons.org/licenses/by… 處得到。

相關文章
相關標籤/搜索