【考前必看三】面試前夕知識點梳理之前端

三、前端

1. 前端性能優化策略

  • 減少 HTTP 請求
  • CSS 放在頭部、避免使用 CSS 表達式
  • JS 放在尾部、精簡 JS
  • 使用外部 CSS 和 JS 文件
  • 刪除重複腳本、壓縮組件
  • 避免重定向
  • 使用緩存
  • 使用 CDN、減少 CDN 查找

2. 跨域解決方案及其原理

同源策略/SOP(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊。所謂同源是指"協議+域名+端口"三者相同,即便兩個不同的域名指向同一個IP地址,也非同源。

常見的跨域場景(不允許通信):

(1)不同協議,同一域名:http://www.domain.com/a.js 和 https://www.domain.com/b.js

(2)同一域名,不同端口:http://www.domain.com:8000/a.js 和 http://www.domain.com/b.js

(3)不同域名:http://www.domain1.com/a.js 和 http://www.domain2.com/b.js

(4)主域相同,子域不同:http://www.domain.com/a.js 和 http://x.domain.com/b.js 和 http://domain.com/c.js

(5)域名和域名對應相同IP:http://www.domain.com/a.js 和 http://192.168.4.12/b.js

跨域解決方案:

(1)通過 jsonp 跨域

(2)document.domain + iframe 跨域:僅限主域相同,子域不同的跨域場景。

(3)location.hash + iframe 跨域:a欲與b跨域相互通信,通過中間頁c來實現。

(4)window.name + iframe 跨域

(5)postMessage 跨域

(6)跨域資源共享(CORS):只需要服務端設置Access-Control-Allow-Origin即可。

(7)nginx 代理跨域

(8)nodejs 中間件代理跨域

(9)WebSocket 協議跨域

跨域解決方案的原理

3. 防抖和節流

防抖函數的作用

防抖函數的作用就是控制函數在一定時間內的執行次數。防抖意味着 N 秒內函數只會被執行一次,如果 N 秒內再次被觸發,則 重新 計算延遲時間。

防抖函數的實現

  • 事件第一次觸發時,timeout 是 null,調用 later(),若 immediate 爲true,那麼立即調用 func.apply(this, params);如果 immediate 爲 false,那麼過 wait 之後,調用 func.apply(this, params)。
  • 事件第二次觸發時,如果 timeout 已經重置爲 null (即 setTimeout 的倒計時結束),那麼流程與第一次觸發時一樣,若 timeout 不爲 null (即 setTimeout 的倒計時未結束),那麼清空定時器,重新開始計時。
function debounce(func, wait, immediate = true) {
    let timeout, result;
    // 延遲執行函數
    const later = (context, args) => setTimeout(() => {
        timeout = null;// 倒計時結束
        if (!immediate) {
            // 執行回調
            result = func.apply(context, args);
            context = args = null;
        }
    }, wait);
    let debounced = function (...params) {
        if (!timeout) {
            timeout = later(this, params);
            if (immediate) {
                // 立即執行
                result = func.apply(this, params);
            }
        } else {
            clearTimeout(timeout);
            // 函數在每個等待時延的結束被調用
            timeout = later(this, params);
        }
        return result;
    }
    // 提供在外部清空定時器的方法
    debounced.cancel = function () {
        clearTimeout(timeout);
        timeout = null;
    };
    return debounced;
};

immediate 爲 true 時,表示函數在每個等待時延的開始被調用。immediate 爲 false 時,表示函數在每個等待時延的結束被調用。 

防抖的應用場景

  1. 搜索框輸入查詢,如果用戶一直在輸入中,沒有必要不停地調用去請求服務端接口,等用戶停止輸入的時候,再調用,設置一個合適的時間間隔,有效減輕服務端壓力。

  2. 表單驗證。

  3. 按鈕提交事件。

  4. 瀏覽器窗口縮放,resize 事件 (如窗口停止改變大小之後重新計算佈局) 等。

節流函數的作用

節流函數的作用是規定一個單位時間,在這個單位時間內最多隻能觸發一次函數執行,如果這個單位時間內多次觸發函數,只能有一次生效。

節流函數的實現

function throttle(func, wait, options = {}) {
    var timeout, context, args, result;
    var previous = 0;
    var later = function () {
        previous = options.leading === false ? 0 : (Date.now() || new Date().getTime());
        timeout = null;
        result = func.apply(context, args);
        if (!timeout) context = args = null;
    };
 
    var throttled = function () {
        var now = Date.now() || new Date().getTime();
        if (!previous && options.leading === false) previous = now;
        //remaining 爲距離下次執行 func 的時間
        //remaining > wait,表示客戶端系統時間被調整過
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        //remaining 小於等於 0,表示事件觸發的間隔時間大於設置的 wait
        if (remaining <= 0 || remaining > wait) {
            if (timeout) {
                // 清空定時器
                clearTimeout(timeout);
                timeout = null;
            }
            // 重置 previous
            previous = now;
            // 執行函數
            result = func.apply(context, args);
            if (!timeout) context = args = null;
        } else if (!timeout && options.trailing !== false) {
            timeout = setTimeout(later, remaining);
        }
        return result;
    };
 
    throttled.cancel = function () {
        clearTimeout(timeout);
        previous = 0;
        timeout = context = args = null;
    };
 
    return throttled;
}

禁用第一次首先執行,傳遞 {leading: false} ;想禁用最後一次執行,傳遞 {trailing: false}。

節流的應用場景

  1. 按鈕點擊事件。

  2. 拖拽事件。

  3. onScoll。

  4. 計算鼠標移動的距離 (mousemove)。

4. link 和 import 的區別

link 屬於 XHTML 標籤,而 @import 是 CSS 提供的。

(1)引用的方式不同:

link(外部引用): <link rel="stylesheet" href="xxx.css"  type="text/css" />
 
@import(導入式): @import url(xxx.css);

(2)放置的位置不同:link 一般放在 head 標籤中,而 @import 必須放在 <style  type="text/css"> 標籤中。

(3)加載方式不同:link 會和 dom 結構一同加載渲染,而 @import 只能等 dom 結構加載完成以後才能加載渲染頁面。

(4)兼容性不同:@import 只能在 IE6 以上才能識別,而 link 是 XHTML 標籤,無兼容問題。

(5)樣式權重不同:link 方式的樣式的權重高於 @import。

(6)改變樣式:link 支持使用 JavaScript 改變樣式,而 @import 不可以。

(7)加載內容不同:link 除了可以加載 css 文件以外,還可以加載 MIME 類型的文件;而 @import 只能加載 css 文件。

5. 瀏覽器內核

  • IE、傲遊、Avant、騰訊TT (trident內核)
  • Mozilla Firefox (gecko內核)
  • Safari (webkit內核)
  • Chrome (Blink內核)
  • Opera (原爲Presto內核,現爲Blink內核)

6. 瀏覽器兼容問題及其解決方案

問題一:在不加樣式控制的情況下,標籤默認的外補丁(margin)和內補丁(padding)不同

解決方案: CSS設置 *{ margin:0; padding:0; }

問題二:塊級屬性標籤 float 之後,如果有左右 margin,那麼在 IE6 中顯示的 margin 比設置的大

解決方案: 在float的標籤樣式中加入 { display: inline; }, 將其轉化爲行內屬性

問題三:行內屬性標籤,在設置 display:block 之後,如果採用 float 佈局,同時又有左右 margin 的情況下,那麼在 IE6 中顯示的間距有 bug

解決方案: 在 { display:block; } 後面加入 { display:inline; display:table; }

問題四:如果給標籤設置較小的高度(一般小於10px),那麼在IE6,IE7和遨遊中這個標籤的高度會超出你設置的高度

在IE6、IE7和遨遊中,這個標籤的高度不受你設置的高度的控制,它會達到默認的行高。這是因爲 IE8 之前的瀏覽器都會給標籤一個最小默認的行高的高度,即使標籤是空的,這個標籤的高度還是會達到默認的行高。

解決方案: 給超出高度的標籤設置 { overflow:hidden; } 或者設置行高 { line-height } 小於你設置的高度

問題五:如果給標籤設置最低高度 min-height,會出現不兼容的情況

解決方案: 如果我們要設置一個標籤的最小高度是200px,需要進行的設置爲:
{
    min-height:200px; 
    height:auto !important; 
    height:200px; 
    overflow:visible;
}

問題六:圖片之間默認有間距

幾個 img 標籤放在一起的時候,有些瀏覽器會有默認的間距,加了問題一中提到的通配符也不起作用。

解決方案: 將 img 設置爲 float 屬性

問題七:格式爲PNG24的圖片在IE6瀏覽器上會出現背景

解決方案:把圖片改成 PNG8 格式

問題八:設置透明度(兼容所有瀏覽器)

.tran_class {   
    filter: alpha(opacity=50); // IE瀏覽器 (trident內核)
    -moz-opacity: 0.5;  // 老版Mozilla firefox (gecko內核) 
    -khtml-opacity: 0.5;   // 老版Safari (webkit內核)
    opacity: 0.5;   // 支持opacity的所有瀏覽器,如:Chrome (Blink內核)、opera (以前是presto內核,現在改用google chrome的Blink內核)
}

問題九: IE6,IE7中 ol 的序號全爲1,不遞增

解決方案: li設置樣式 { display: list-item }

問題十: IE6,IE7不支持 display:inline-block

解決方案: 設置 inline, 並觸發 haslayout
{ display:inline-block; *display:inline; *zoom:1 }

問題十一: 使用 hack 解決瀏覽器兼容問題

不同的瀏覽器對CSS的解析不同,會導致生成的頁面效果不同。通過使用 hack 可以解決瀏覽器兼容問題(針對的更多是 老式/舊版本 瀏覽器),但不推薦使用,因爲當代碼量多時,編寫複雜度會變高,還可能會在瀏覽器更新之後產生更多的兼容問題。

hack 可以理解爲不同瀏覽器識別的標識符。

(1)五大瀏覽器的hack

div {
    transform: rotate(90deg);         /* 標準模式 */
    -moz-transform: rotate(90deg);    /* Firefox */
    -webkit-transform: rotate(90deg); /* Safari and Chrome */
    -o-transform: rotate(90deg);      /* Opera */
    -ms-transform: rotate(90deg);     /* IE */
}

(2)CSS屬性hack

IE6能識別 下劃線_ 和 星號* ,但不能識別 !important
IE7能識別 星號* 和 !important ,但不識別 下劃線_
Firefox 能識別 !important ,但不識別 下劃線_ 和 星號*
書寫順序:FF IE7 IE6
 
比如這樣一個CSS設置:
{ 
    height:300px; 
    *height:200px; 
    _height:100px; 
}
 
在IE6中從上往下讀,直到_height,把高度設置成了100px;
在IE7中從上往下讀,直到*height,把高度設置成了200px;
在其他瀏覽器中,把高度設置成了300px。

(3)CSS選擇符hack

IE6能識別*html .class{}
IE7能識別*+html .class{} 或者 *:first-child+html .class{}

(4)條件註釋法:這種方式是 IE 瀏覽器專有的 hack 方式,微軟官方推薦使用。 

問題十二:獲取自定義屬性

IE瀏覽器下,可以使用獲取常規屬性的方法來獲取自定義屬性,也可以使用getAttribute()獲取自定義屬性。

Firefox瀏覽器下,只能使用getAttribute()獲取自定義屬性。

解決方案:統一使用 getAttribute() 獲取自定義屬性

問題十三:Chrome 瀏覽器的中文界面下默認會將小於 12px 的文本強制按照 12px 顯示

解決方案:加入 CSS 屬性 {-webkit-text-size-adjust: none; }

問題十四:超鏈接訪問過後 hover 樣式就不出現了;被點擊訪問過的超鏈接樣式不再具有 hover 和 active 了

解決方案:改變 CSS 屬性的排列順序:
L-V-H-A :  a:link {} a:visited {} a:hover {} a:active {} 

問題十五:even對象

IE瀏覽器下,even對象有x,y屬性,但是沒有pageX,pageY屬性。

Firefox瀏覽器下,event對象有pageX,pageY屬性,但是沒有x,y屬性。

解決方案:條件註釋
缺點:在IE瀏覽器下可能會增加額外的 HTTP 請求。

7. 從輸入網址到最後瀏覽器呈現頁面內容,中間發生了什麼?

(1)輸入網址,瀏覽器,發送UDP包給DNS服務器,通過DNS解析得到網址的IP地址(即服務器的IP),並將IP地址緩存。

(2)客戶端(瀏覽器)和服務器端之間建立TCP連接:由於TCP郵差需要知道4個東西(本機IP,本機端口,服務器IP,服務器端口),現在只知道了本機IP,服務器IP, 兩個端口怎麼辦?其中,本機端口很簡單,操作系統可以給瀏覽器隨機分配一個, 服務器端口更簡單,用的是一個“衆所周知”的端口,HTTP服務就是80(HTTPS服務就是443), 我們直接告訴TCP郵差就行。經過三次握手以後,客戶端和服務器端的TCP連接就建立起來了! 

(3)瀏覽器發送HTTP請求。

(4)Web服務器處理請求,並將HTTP Response(一個HTML頁面)返回給瀏覽器。

(5)瀏覽器再次發起請求:由於這個HTML頁面中可能引用了大量其他資源,例如JS文件,CSS文件,圖片等,這些資源也位於服務器端,並且可能位於另外一個域名下面。所以瀏覽器只好一個個地下載,從使用DNS獲取IP開始,之前做過的事情還要再來一遍。

(6)當服務器把JS,CSS這些文件發送給瀏覽器時,會告訴瀏覽器這些文件什麼時候過期(使用Cache-Control或者Expire),瀏覽器可以把文件緩存到本地,當第二次請求同樣的文件時,如果不過期,直接從本地取就可以了。如果過期了,瀏覽器就可以詢問服務器端,文件有沒有修改過?(依據是上一次服務器發送的Last-Modified和ETag),如果沒有修改過(304 Not Modified),還可以使用緩存。否則的話服務器就會把最新的文件發回到瀏覽器。

(7)現在瀏覽器擁有了 HTML、CSS 和 JavaScript(可以修改 DOM Tree),開始進行渲染

  • HTML,瀏覽器把它解析成 DOM Tree;CSS,瀏覽器把它解析成 CSS Rule Tree
  • DOM Tree 和 CSS Rule Tree 解析完成之後,被附加到一起,形成渲染樹 Render Tree
  • (重排 - Reflow) 計算節點信息:根據渲染樹計算每個節點的幾何信息
  • (重繪 - Repaint) 渲染繪製:根據計算好的節點信息,渲染繪製整個頁面

最後,我們就能看到呈現的頁面了。

8. 重排和重繪

重排:若渲染樹的部分節點更新,且尺寸變化,就會發生重排。

重繪:若渲染樹的部分節點更新,但不改變其他節點,就會發生重繪。

PS:重繪不一定導致重排,但重排一定會導致重繪。重排會產生比重繪更大的開銷。

觸發重排:

  • (1)頁面第一次渲染:在頁面發生首次渲染的時候,所有組件都要進行首次佈局,這是開銷最大的一次重排
  • (2)瀏覽器窗口尺寸改變
  • (3)元素位置和尺寸(寬、高、內外邊距、邊框等)發生改變的時候
  • (4)增加或刪除DOM節點
  • (5)內容發生改變(文字數量或圖片大小等等)
  • (6)元素字體大小變化
  • (7)激活CSS僞類(例如::hover) 
  • (8)增加或修改樣式,設置style屬性
  • (9)查詢某些屬性或調用某些方法,如:調用getComputedStyle方法,或者IE裏的currentStyle時,也會觸發重排
  • (10)display:none —— 設置該屬性的元素將會消失,不佔據空間

觸發重繪:

  • (1)visibility:hidden —— visibility 屬性規定元素是否可見。即使不可見的元素也會佔據頁面上的空間。
  • (2)outline —— outline (輪廓)是繪製於元素周圍的一條線,位於邊框邊緣的外圍。輪廓線不會佔據空間,也不一定是矩形。
  • (3)背景顏色:color、background-color

如何減少重排和重繪以提升頁面性能:

  • (1)樣式集中改變。
  • (2)DOM離線化。
  • (3)批量添加DOM。
  • (4)複製節點,在副本中修改,然後直接替換當前的節點。
  • (5)降低受影響的節點:在頁面頂部插入節點將影響後續所有節點,而絕對定位元素的改變會影響較少的元素,將position屬性設置爲absolute或fixed
  • (6)分離讀寫操作。
  • (7)緩存佈局信息。
  • (8)使用 css spirit,也叫 css 精靈,它將所有的圖片放到一張圖片上,然後通過定位來實現圖片的使用。

參考:https://www.imooc.com/article/45936

END

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章