面試題來源於個人項目 「前端面試與進階指南」
本章關於瀏覽器原理部分的內容主要來源於瀏覽器工做原理,這是一篇很長的文章,能夠算上一本小書了,有精力的很是建議閱讀。css
瀏覽器/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 |
圖:瀏覽器的主要組件。
值得注意的是,和大多數瀏覽器不一樣,Chrome 瀏覽器的每一個標籤頁都分別對應一個呈現引擎實例。每一個標籤頁都是一個獨立的進程。html
瀏覽器會『從右往左』解析CSS選擇器。前端
咱們知道DOM Tree與Style Rules合成爲 Render Tree,其實是須要將Style Rules附着到DOM Tree上,所以須要根據選擇器提供的信息對DOM Tree進行遍歷,才能將樣式附着到對應的DOM元素上。html5
如下這段css爲例java
.mod-nav h3 span {font-size: 16px;}
咱們對應的DOM Tree 以下node
若從左向右的匹配,過程是:nginx
若是從右至左的匹配:git
後者匹配性能更好,是由於從右向左的匹配在第一步就篩選掉了大量的不符合條件的最右節點(葉子節點);而從左向右的匹配規則的性能都浪費在了失敗的查找上面。程序員
Treegithub
單單改變元素的外觀,確定不會引發網頁從新生成佈局,但當瀏覽器完成重排以後,將會從新繪製受到這次重排影響的部分
重排和重繪代價是高昂的,它們會破壞用戶體驗,而且讓UI展現很是遲緩,而相比之下重排的性能影響更大,在二者沒法避免的狀況下,通常咱們寧肯選擇代價更小的重繪。
『重繪』不必定會出現『重排』,『重排』必然會出現『重繪』。
任何改變用來構建渲染樹的信息都會致使一次重排或重繪:
咱們每每經過改變class的方式來集中改變樣式
// 判斷是不是黑色系樣式 const theme = isDark ? 'dark' : 'light' // 根據判斷來設置不一樣的class ele.setAttribute('className', theme)
咱們能夠經過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);
將元素提高爲合成層有如下優勢:
提高合成層的最好方式是使用 CSS 的 will-change 屬性:
#target { will-change: transform; }
關於合成層的詳解請移步 無線性能優化:Composite
短輪詢的原理很簡單,每隔一段時間客戶端就發出一個請求,去獲取服務器最新的數據,必定程度上模擬實現了即時通信。
comet有兩種主要實現手段,一種是基於 AJAX 的長輪詢(long-polling)方式,另外一種是基於 Iframe 及 htmlfile 的流(streaming)方式,一般被叫作長鏈接。
具體兩種手段的操做方法請移步 Comet技術詳解:基於HTTP長鏈接的Web端實時通訊技術
長輪詢優缺點:
長鏈接優缺點:
使用指南請看 Server-Sent Events 教程
SSE(Server-Sent Event,服務端推送事件)是一種容許服務端向客戶端推送新數據的HTML5技術。
使用指南請看 WebSocket 教程
Websocket是一個全新的、獨立的協議,基於TCP協議,與http協議兼容、卻不會融入http協議,僅僅做爲html5的一部分,其做用就是在服務器和客戶端之間創建實時的雙向通訊。
後面性能優化部分會用到,先作了解
Web Worker 的做用,就是爲 JavaScript 創造多線程環境,容許主線程建立 Worker 線程,將一些任務分配給後者運行
Web Worker教程
後面性能優化部分會用到,先作了解
Service workers 本質上充當Web應用程序與瀏覽器之間的代理服務器,也能夠在網絡可用時做爲瀏覽器和網絡間的代理,建立有效的離線體驗。
Service workers教程
同源策略限制了從同一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的重要安全機制。
同源是指"協議+域名+端口"三者相同,即使兩個不一樣的域名指向同一個ip地址,也非同源。
下表給出了相對http://store.company.com/dir/...:
瀏覽器中的大部份內容都是受同源策略限制的,可是如下三個標籤能夠不受限制:
<img src=XXX>
<link href=XXX>
<script src=XXX>
跨域是個比較古老的命題了,歷史上跨域的實現手段有不少,咱們如今主要介紹三種比較主流的跨域方案,其他的方案咱們就不深刻討論了,由於使用場景不多,也不必記這麼多奇技淫巧。
jsonp本質上是一個Hack,它利用<script>
標籤不受同源策略限制的特性進行跨域操做。
jsonp優勢:
jsonp的缺點:
<script>
標籤只能get)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) 是一種機制,它使用額外的 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是一款極其強大的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; } } }
其他方案來源於 九種跨域方式
參考文章:
想要實時關注筆者最新的文章和最新的文檔更新請關注公衆號程序員面試官,後續的文章會優先在公衆號更新.
簡歷模板: 關注公衆號回覆「模板」獲取
《前端面試手冊》: 配套於本指南的突擊手冊,關注公衆號回覆「fed」獲取