1. 程式人生 > >11道瀏覽器原理面試題

11道瀏覽器原理面試題

瀏覽器與新技術

面試題來源於我的專案「前端面試與進階指南」

本章關於瀏覽器原理部分的內容主要來源於瀏覽器工作原理,這是一篇很長的文章,可以算上一本小書了,有精力的非常建議閱讀。

常見的瀏覽器核心有哪些?

瀏覽器/RunTime 核心(渲染引擎) JavaScript 引擎
Chrome Blink(28~)
Webkit(Chrome 27)
V8
FireFox Gecko SpiderMonkey
Safari Webkit JavaScriptCore
Edge EdgeHTML Chakra(for JavaScript)
IE Trident Chakra(for JScript)
PhantomJS Webkit JavaScriptCore
Node.js - V8

瀏覽器的主要組成部分是什麼?

  1. 使用者介面 - 包括位址列、前進/後退按鈕、書籤選單等。除了瀏覽器主視窗顯示的您請求的頁面外,其他顯示的各個部分都屬於使用者介面。
  2. 瀏覽器引擎 - 在使用者介面和呈現引擎之間傳送指令。
  3. 呈現引擎 - 負責顯示請求的內容。如果請求的內容是 HTML,它就負責解析 HTML 和 CSS 內容,並將解析後的內容顯示在螢幕上。
  4. 網路 - 用於網路呼叫,比如 HTTP 請求。其介面與平臺無關,併為所有平臺提供底層實現。
  5. 使用者介面後端 - 用於繪製基本的視窗小部件,比如組合框和視窗。其公開了與平臺無關的通用介面,而在底層使用作業系統的使用者介面方法。
  6. JavaScript 直譯器。用於解析和執行 JavaScript 程式碼。
  7. 資料儲存。這是持久層。瀏覽器需要在硬碟上儲存各種資料,例如 Cookie。新的 HTML 規範 (HTML5) 定義了“網路資料庫”,這是一個完整(但是輕便)的瀏覽器內資料庫。

圖:瀏覽器的主要元件。

值得注意的是,和大多數瀏覽器不同,Chrome 瀏覽器的每個標籤頁都分別對應一個呈現引擎例項。每個標籤頁都是一個獨立的程序。

瀏覽器是如何渲染UI的?

  1. 瀏覽器獲取HTML檔案,然後對檔案進行解析,形成DOM Tree
  2. 與此同時,進行CSS解析,生成Style Rules
  3. 接著將DOM Tree與Style Rules合成為 Render Tree
  4. 接著進入佈局(Layout)階段,也就是為每個節點分配一個應出現在螢幕上的確切座標
  5. 隨後呼叫GPU進行繪製(Paint),遍歷Render Tree的節點,並將元素呈現出來

瀏覽器如何解析css選擇器?

瀏覽器會『從右往左』解析CSS選擇器。

我們知道DOM Tree與Style Rules合成為 Render Tree,實際上是需要將Style Rules附著到DOM Tree上,因此需要根據選擇器提供的資訊對DOM Tree進行遍歷,才能將樣式附著到對應的DOM元素上。

以下這段css為例

.mod-nav h3 span {font-size: 16px;}

我們對應的DOM Tree 如下

若從左向右的匹配,過程是:

  1. 從 .mod-nav 開始,遍歷子節點 header 和子節點 div
  2. 然後各自向子節點遍歷。在右側 div 的分支中
  3. 最後遍歷到葉子節點 a ,發現不符合規則,需要回溯到 ul 節點,再遍歷下一個 li-a,一顆DOM樹的節點動不動上千,這種效率很低。

如果從右至左的匹配:

  1. 先找到所有的最右節點 span,對於每一個 span,向上尋找節點 h3
  2. 由 h3再向上尋找 class=mod-nav 的節點
  3. 最後找到根元素 html 則結束這個分支的遍歷。

後者匹配效能更好,是因為從右向左的匹配在第一步就篩選掉了大量的不符合條件的最右節點(葉子節點);而從左向右的匹配規則的效能都浪費在了失敗的查詢上面。

DOM Tree是如何構建的?

  1. 轉碼: 瀏覽器將接收到的二進位制資料按照指定編碼格式轉化為HTML字串
  2. 生成Tokens: 之後開始parser,瀏覽器會將HTML字串解析成Tokens
  3. 構建Nodes: 對Node新增特定的屬性,通過指標確定 Node 的父、子、兄弟關係和所屬 treeScope
  4. 生成DOM Tree: 通過node包含的指標確定的關係構建出DOM
    Tree

瀏覽器重繪與重排的區別?

  • 重排: 部分渲染樹(或者整個渲染樹)需要重新分析並且節點尺寸需要重新計算,表現為重新生成佈局,重新排列元素
  • 重繪: 由於節點的幾何屬性發生改變或者由於樣式發生改變,例如改變元素背景色時,螢幕上的部分內容需要更新,表現為某些元素的外觀被改變

單單改變元素的外觀,肯定不會引起網頁重新生成佈局,但當瀏覽器完成重排之後,將會重新繪製受到此次重排影響的部分

重排和重繪代價是高昂的,它們會破壞使用者體驗,並且讓UI展示非常遲緩,而相比之下重排的效能影響更大,在兩者無法避免的情況下,一般我們寧可選擇代價更小的重繪。

『重繪』不一定會出現『重排』,『重排』必然會出現『重繪』。

如何觸發重排和重繪?

任何改變用來構建渲染樹的資訊都會導致一次重排或重繪:

  • 新增、刪除、更新DOM節點
  • 通過display: none隱藏一個DOM節點-觸發重排和重繪
  • 通過visibility: hidden隱藏一個DOM節點-只觸發重繪,因為沒有幾何變化
  • 移動或者給頁面中的DOM節點新增動畫
  • 新增一個樣式表,調整樣式屬性
  • 使用者行為,例如調整視窗大小,改變字號,或者滾動。

如何避免重繪或者重排?

集中改變樣式

我們往往通過改變class的方式來集中改變樣式

// 判斷是否是黑色系樣式
const theme = isDark ? 'dark' : 'light'

// 根據判斷來設定不同的class
ele.setAttribute('className', theme)

使用DocumentFragment

我們可以通過createDocumentFragment建立一個遊離於DOM樹之外的節點,然後在此節點上批量操作,最後插入DOM樹中,因此只觸發一次重排

var fragment = document.createDocumentFragment();

for (let i = 0;i<10;i++){
  let node = document.createElement("p");
  node.innerHTML = i;
  fragment.appendChild(node);
}

document.body.appendChild(fragment);

提升為合成層

將元素提升為合成層有以下優點:

  • 合成層的點陣圖,會交由 GPU 合成,比 CPU 處理要快
  • 當需要 repaint 時,只需要 repaint 本身,不會影響到其他的層
  • 對於 transform 和 opacity 效果,不會觸發 layout 和 paint

提升合成層的最好方式是使用 CSS 的 will-change 屬性:

#target {
  will-change: transform;
}

關於合成層的詳解請移步無線效能優化:Composite

前端如何實現即時通訊?

短輪詢

短輪詢的原理很簡單,每隔一段時間客戶端就發出一個請求,去獲取伺服器最新的資料,一定程度上模擬實現了即時通訊。

  • 優點:相容性強,實現非常簡單
  • 缺點:延遲性高,非常消耗請求資源,影響效能

comet

comet有兩種主要實現手段,一種是基於 AJAX 的長輪詢(long-polling)方式,另一種是基於 Iframe 及 htmlfile 的流(streaming)方式,通常被叫做長連線。

具體兩種手段的操作方法請移步Comet技術詳解:基於HTTP長連線的Web端實時通訊技術

長輪詢優缺點:

  • 優點:相容性好,資源浪費較小
  • 缺點:伺服器hold連線會消耗資源,返回資料順序無保證,難於管理維護

長連線優缺點:

  • 優點:相容性好,訊息即時到達,不發無用請求
  • 缺點:伺服器維護長連線消耗資源

SSE

使用指南請看Server-Sent Events 教程

SSE(Server-Sent Event,服務端推送事件)是一種允許服務端向客戶端推送新資料的HTML5技術。

  • 優點:基於HTTP而生,因此不需要太多改造就能使用,使用方便,而websocket非常複雜,必須藉助成熟的庫或框架
  • 缺點:基於文字傳輸效率沒有websocket高,不是嚴格的雙向通訊,客戶端向服務端傳送請求無法複用之前的連線,需要重新發出獨立的請求

Websocket

使用指南請看WebSocket 教程

Websocket是一個全新的、獨立的協議,基於TCP協議,與http協議相容、卻不會融入http協議,僅僅作為html5的一部分,其作用就是在伺服器和客戶端之間建立實時的雙向通訊。

  • 優點:真正意義上的實時雙向通訊,效能好,低延遲
  • 缺點:獨立與http的協議,因此需要額外的專案改造,使用複雜度高,必須引入成熟的庫,無法相容低版本瀏覽器

Web Worker

後面效能優化部分會用到,先做了解

Web Worker 的作用,就是為 JavaScript 創造多執行緒環境,允許主執行緒建立 Worker 執行緒,將一些任務分配給後者執行

Web Worker教程

Service workers

後面效能優化部分會用到,先做了解

Service workers 本質上充當Web應用程式與瀏覽器之間的代理伺服器,也可以在網路可用時作為瀏覽器和網路間的代理,建立有效的離線體驗。

Service workers教程

什麼是瀏覽器同源策略?

同源策略限制了從同一個源載入的文件或指令碼如何與來自另一個源的資源進行互動。這是一個用於隔離潛在惡意檔案的重要安全機制。

同源是指"協議+域名+埠"三者相同,即便兩個不同的域名指向同一個ip地址,也非同源。

下表給出了相對http://store.company.com/dir/page.html同源檢測的示例:

瀏覽器中的大部分內容都是受同源策略限制的,但是以下三個標籤可以不受限制:

  • <img src=XXX>
  • <link href=XXX>
  • <script src=XXX>

如何實現跨域?

跨域是個比較古老的命題了,歷史上跨域的實現手段有很多,我們現在主要介紹三種比較主流的跨域方案,其餘的方案我們就不深入討論了,因為使用場景很少,也沒必要記這麼多奇技淫巧。

最經典的跨域方案jsonp

jsonp本質上是一個Hack,它利用<script>標籤不受同源策略限制的特性進行跨域操作。

jsonp優點:

  • 實現簡單
  • 相容性非常好

jsonp的缺點:

  • 只支援get請求(因為<script>標籤只能get)
  • 有安全性問題,容易遭受xss攻擊
  • 需要服務端配合jsonp進行一定程度的改造

jsonp的實現:

function JSONP({  
  url,
  params,
  callbackKey,
  callback
}) {
  // 在引數裡制定 callback 的名字
  params = params || {}
  params[callbackKey] = 'jsonpCallback'
    // 預留 callback
  window.jsonpCallback = callback
    // 拼接引數字串
  const paramKeys = Object.keys(params)
  const paramString = paramKeys
    .map(key => `${key}=${params[key]}`)
    .join('&')
    // 插入 DOM 元素
  const script = document.createElement('script')
  script.setAttribute('src', `${url}?${paramString}`)
  document.body.appendChild(script)
}

JSONP({  
  url: 'http://s.weibo.com/ajax/jsonp/suggestion',
  params: {
    key: 'test',
  },
  callbackKey: '_cb',
  callback(result) {
    console.log(result.data)
  }
})

最流行的跨域方案cors

cors是目前主流的跨域解決方案,跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器 讓執行在一個 origin (domain) 上的Web應用被准許訪問來自不同源伺服器上的指定的資源。當一個資源從與該資源本身所在的伺服器不同的域、協議或埠請求一個資源時,資源會發起一個跨域 HTTP 請求。

如果你用express,可以這樣在後端設定

//CORS middleware
var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', 'http://example.com');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');

    next();
}

//...
app.configure(function() {
    app.use(express.bodyParser());
    app.use(express.cookieParser());
    app.use(express.session({ secret: 'cool beans' }));
    app.use(express.methodOverride());
    app.use(allowCrossDomain);
    app.use(app.router);
    app.use(express.static(__dirname + '/public'));
});

在生產環境中建議用成熟的開源中介軟體解決問題。

最方便的跨域方案Nginx

nginx是一款極其強大的web伺服器,其優點就是輕量級、啟動快、高併發。

現在的新專案中nginx幾乎是首選,我們用node或者java開發的服務通常都需要經過nginx的反向代理。

反向代理的原理很簡單,即所有客戶端的請求都必須先經過nginx的處理,nginx作為代理伺服器再講請求轉發給node或者java服務,這樣就規避了同源策略。

#程序, 可更具cpu數量調整
worker_processes  1;

events {
    #連線數
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    #連線超時時間,伺服器會在這個時間過後關閉連線。
    keepalive_timeout  10;

    # gizp壓縮
    gzip  on;

    # 直接請求nginx也是會報跨域錯誤的這裡設定允許跨域
    # 如果代理地址已經允許跨域則不需要這些, 否則報錯(雖然這樣nginx跨域就沒意義了)
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Headers X-Requested-With;
    add_header Access-Control-Allow-Methods GET,POST,OPTIONS;

    # srever模組配置是http模組中的一個子模組,用來定義一個虛擬訪問主機
    server {
        listen       80;
        server_name  localhost;
        
        # 根路徑指到index.html
        location / {
            root   html;
            index  index.html index.htm;
        }

        # localhost/api 的請求會被轉發到192.168.0.103:8080
        location /api {
            rewrite ^/b/(.*)$ /$1 break; # 去除本地介面/api字首, 否則會出現404
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://192.168.0.103:8080; # 轉發地址
        }
        
        # 重定向錯誤頁面到/50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }

}

其它跨域方案

  1. HTML5 XMLHttpRequest 有一個API,postMessage()方法允許來自不同源的指令碼採用非同步方式進行有限的通訊,可以實現跨文字檔、多視窗、跨域訊息傳遞。
  2. WebSocket 是一種雙向通訊協議,在建立連線之後,WebSocket 的 server 與 client 都能主動向對方傳送或接收資料,連線建立好了之後 client 與 server 之間的雙向通訊就與 HTTP 無關了,因此可以跨域。
  3. window.name + iframe:window.name屬性值在不同的頁面(甚至不同域名)載入後依舊存在,並且可以支援非常長的 name 值,我們可以利用這個特點進行跨域。
  4. location.hash + iframe:a.html欲與c.html跨域相互通訊,通過中間頁b.html來實現。 三個頁面,不同域之間利用iframe的location.hash傳值,相同域之間直接js訪問來通訊。
  5. document.domain + iframe: 該方式只能用於二級域名相同的情況下,比如 a.test.com 和 b.test.com 適用於該方式,我們只需要給頁面新增 document.domain ='test.com' 表示二級域名都相同就可以實現跨域,兩個頁面都通過js強制設定document.domain為基礎主域,就實現了同域。

其餘方案來源於九種跨域方式


參考文章:

  • 為什麼 CSS 選擇器解析的時候是從右往左?

公眾號

想要實時關注筆者最新的文章和最新的文件更新請關注公眾號程式設計師面試官,後續的文章會優先在公眾號更新.

簡歷模板: 關注公眾號回覆「模板」獲取

《前端面試手冊》: 配套於本指南的突擊手冊,關注公眾號回覆「fed」獲取

相關推薦

11瀏覽器原理試題

瀏覽器與新技術 面試題來源於我的專案「前端面試與進階指南」 本章關於瀏覽器原理部分的內容主要來源於瀏覽器工作原理,這是一篇很長的文章,可以算上一本小書了,有精力的非常建議閱讀。 常見的瀏覽器核心有哪些? 瀏覽器/RunTime 核心(渲染引擎) JavaScript 引擎 Chrome Bl

深入解答11Python基礎試題

傳參 default .get python基礎 說明 默認值 get 根據 none 1. Python的參數傳遞是值傳遞還是引 舉例說明Python函數參數傳遞的幾種形式,並說明函數傳參是值傳遞還是引用傳遞 一、位置參數 調用函數時根據函數定義的參數位置來傳遞參數。

精選11Java技術試題並有答案(包含部分阿裏和華為的試題

mit 高度 nth erro 多線程 edi GC expire 棧溢出 JVM的類加載機制是什麽?有哪些實現方式? 類加載機制: 類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法去內,然後在堆區創建一個java.lang.Cl

100Java基礎試題

nvi ++i 成員 取出 並發 字符串長度 反轉 static container 1.什麽是B/S架構?什麽是C/S架構 B/S(Browser/Server),瀏覽器/服務器程序 C/S(Client/Server),客戶端/服務端,桌面應用程序 2.你

緊急整理了 20 Spring Boot 試題,我經常拿來面試別人!

面試了一些人,簡歷上都說自己熟悉 Spring Boot, 或者說正在學習 Spring Boot,一問他們時,都只停留在簡單的使用階段,很多東西都不清楚,也讓我對面試者大失所望。 下面,我給大家總結下有哪些 Spring Boot 的面試題,這是我經常拿來問面試者的,希望對你有幫助。

吐血整理 20 Spring Boot 試題,我經常拿來面試別人!

面試了一些人,簡歷上都說自己熟悉 Spring Boot, 或者說正在學習 Spring Boot,一問他們時,都只停留在簡單的使用階段,很多東西都不清楚,也讓我對面試者大失所望。 下面,我給大家總結下有哪些 Spring Boot 的面試題,這是我經常拿來問面試者的,希望對你有幫助。 1、什麼是 Spr

Java基礎試題你真的會嗎?

你咱不往下看,先想想你的答案是什麼? 這裡先來聊聊String的intern()方法是幹什麼的? intern方法是一個native方法,空口無憑,咱們還是可以看看Stirng的原始碼 從方法的註釋咱們可以知道,它的作用: 1:如果字串常量池中已經包含一個等於此Sti

27Redis精選試題,你會做幾題?

最近面試了幾家公司,都問到了Redis相關問題,當時準備面試時忽略了這方面內容,面試結果就可想而知了。面試回來後,收集了身邊朋友面試時遇到的關於redis的問題,進行了總結,記錄一下以便之後面試有所參考。 1、什麼是Redis?簡述它的優缺點? Redis的全稱是:Remote Dict

乾貨 | 45CSS基礎試題(附答案)

  1、 介紹一下標準的CSS的盒子模型?與低版本IE的盒子模型有什麼不同的? 標準盒子模型:寬度=內容的寬度(content)+ border + padding + margin 低版本IE盒子模型:寬度=內容寬度(content+border+padding)+ mar

18年11月下,試題積累

map遍歷方法 1、Iterator遍歷 Iterator<Map.Entry<String,String>> it = map.entrySet().iterator(); while(it.hasNext()){ Map.En

18年11月上,試題積累(深圳安碩資訊試題包含其中)

平安外包-安碩資訊面試題 1.程式設計:有一個數列,它的第一項為00,第二項為1,以後每一項都是它的前兩項之和,試產生改數列的前20項,並按從小到大排序列顯示,每行顯示5個元素。 2.編寫一個java程式實現多執行緒,線上程中輸出執行緒的名字,每隔300毫秒輸出一次,共輸出10次。

30python真實試題(蒐集到的,看看其實都是基礎)

1、一行程式碼實現1-100之間和 In [1]: sum(range(0,101)) Out[1]: 5050 2、如何在一個函式內部修改全域性變數 利用global修改全域性變數 In [2]: a = 10 In [3]: def fn(): ...: global a

30python真實試題(附答案)

  最近收集整理了100道python真實面試筆試題,並自己做了一些,希望能幫助大家,順利早日找到工作,限於篇幅問題,本文附有30道面試題計算答案。                學習Python中有

精選22Spring Boot 試題(上)

總結有關於spring boot的面試題,不看答案你是否全部都能答出來? 問題一 什麼是Spring Boot? 多年來,隨著新功能的增加,spring變得越來越複雜。只需訪問https://spring.io/projects頁面,我們就會看到可以在我們的應

115經典Java試題及答案解析,掌握這些還怕面試官不下”跪“

面向物件程式設計(OOP) Java是一個支援併發、基於類和麵向物件的計算機程式語言。下面列出了面向物件軟體開發的優點: 程式碼開發模組化,更易維護和修改。 程式碼複用。 增強程式碼的可靠性和靈活性。 增加程式碼的可理解性。 面向物件程式設計有很多重要的特性,比如

C++ STL和幾經典的試題

https://blog.csdn.net/dingyahui123/article/details/78644235   C++ STL 的實現: 1.vector:  底層資料結構為陣列 ,支援快速隨機訪問。 2.list:   

Java 程式設計師必須掌握的 8 資料結構試題,你會幾

瑞士電腦科學家Niklaus Wirth在1976年寫了一本書,名為《演算法+資料結構=程式設計》。 40多年後,這個等式仍被奉為真理。這就是為什麼在面試過程中,需要考察軟體工程師對資料結構的理解。 幾乎所有的問題都需要面試者對資料結構有深刻的理解。無論你是初入職場的

10深度學習試題,小夥伴檢測一下自己吧!

深度學習 1. 視覺計算任務有哪些,你怎麼分類 ? 我把任務分為畫素級別、目標級別、理解級別。 畫素級別的任務一般是傳統的影象處理任務,他們不需要用到影象的語義資訊,或者最多用到底層特徵(比如影象的邊緣、紋理),這些任務有影象增強、傳統的影象復原(如去噪、去模糊)、傳統的影象分

Spring Boot 試題 吐血整理 20 Spring Boot 試題,我經常拿來面試別人!

吐血整理 20 道 Spring Boot 面試題,我經常拿來面試別人!   面試了一些人,簡歷上都說自己熟悉 Spring Boot, 或者說正在學習 Spring Boot,一問他們時,都只停留在簡單的使用階段,很多東西都不清楚,也讓我對面試者大失所望。 下面,我給

100Java經典試題及答案解析

作用域public,private,protected,以及不寫時的區別 答:區別如下: 作用域 當前類 同一package 子孫類 其他package public √ √ √ √ protected √ √ √ × friendly √ √ ×