今天說說浏覽器相關問題:
- 常見的浏覽器核心,參見下表:
浏覽器/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:隻有原生Chrome中存在一種MimeType“application/vnd.chromium.remoting-viewer”,由此可以判斷浏覽器是加殼Chrome或是原生Chrome。
判斷是否為IE浏覽器:隻有IE核心的浏覽器存在ActiveXObject對象。由此可以判斷是否為IE浏覽
-
從輸入 URL 到頁面加載完成,發生了什麼?
首先我們需要通過 DNS(域名解析系統)将 URL 解析為對應的 IP 位址,然後與這個 IP 位址确定的那台伺服器建立起 TCP 網絡連接配接,随後我們向服務端抛出我們的 HTTP 請求,服務端處理完我們的請求之後,把目标資料放在 HTTP 響應裡傳回給用戶端,拿到響應資料的浏覽器就可以開始走一個渲染的流程。渲染完畢,頁面便呈現給了使用者。
1) DNS 解析:
2) TCP 連接配接:
3) HTTP 請求抛出
4) 服務端處理請求,HTTP 響應傳回
5) 浏覽器拿到響應資料,解析響應内容,把解析的結果展示給使用者
-
浏覽器重繪與重排的差別?
重排: 部分渲染樹(或者整個渲染樹)需要重新分析并且節點尺寸需要重新計算,表現為重新生成布局,重新排列元素
重繪: 由于節點的幾何屬性發生改變或者由于樣式發生改變,例如改變元素背景色時,螢幕上的部分内容需要更新,表現為某些元素的外觀被改變
單單改變元素的外觀,肯定不會引起網頁重新生成布局,但當浏覽器完成重排之後,将會重新繪制受到此次重排影響的部分
重排和重繪代價是高昂的,它們會破壞使用者體驗,并且讓UI展示非常遲緩,而相比之下重排的性能影響更大,在兩者無法避免的情況下,一般我們甯可選擇代價更小的重繪。
『重繪』不一定會出現『重排』,『重排』必然會出現『重繪』。
-
如何觸發重排和重繪?
任何改變用來建構渲染樹的資訊都會導緻一次重排或重繪:
添加、删除、更新DOM節點
通過display: none隐藏一個DOM節點-觸發重排和重繪
通過visibility: hidden隐藏一個DOM節點-隻觸發重繪,因為沒有幾何變化
移動或者給頁面中的DOM節點添加動畫
添加一個樣式表,調整樣式屬性
使用者行為,例如調整視窗大小,改變字号,或者滾動
-
如何避免重繪或者重排?
集中改變樣式:通過改變class的方式來集中改變樣式
使用DocumentFragment:通過createDocumentFragment建立一個遊離于DOM樹之外的節點,然後在此節點上批量操作,最後插入DOM樹中,是以隻觸發一次重排// 判斷是否是黑色系樣式 const theme = isDark ? 'dark' : 'light' // 根據判斷來設定不同的class ele.setAttribute('className', theme)
提升為合成層:提升合成層的最好方式是使用 CSS 的 will-change 屬性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);
#target { will-change: transform; }
-
前端如何實作即時通訊?
1)短輪詢
2)comet
3)SSE
4)Websocket
5)Web Worker
6)Service workers
HTTP 協定有一個缺陷:通信隻能由用戶端發起。舉例來說,我們想了解今天的天氣,隻能是用戶端向伺服器送出請求,伺服器傳回查詢結果。HTTP 協定做不到伺服器主動向用戶端推送資訊。這種單向請求的特點,注定了如果伺服器有連續的狀态變化,用戶端要獲知就非常麻煩。我們隻能使用"輪詢":每隔一段時候,就發出一個詢問,了解伺服器有沒有新的資訊。最典型的場景就是聊天室。輪詢的效率低,非常浪費資源(因為必須不停連接配接,或者 HTTP 連接配接始終打開)。是以,可以用另一種方法 WebSocket 。
-
Websocket
WebSocket 協定最大特點就是,伺服器可以主動向用戶端推送資訊,用戶端也可以主動向伺服器發送資訊,是真正的雙向平等對話,屬于伺服器推送技術的一種。
特點包括:
(1)建立在 TCP 協定之上,伺服器端的實作比較容易。
(2)與 HTTP 協定有着良好的相容性。預設端口也是80和443,并且握手階段采用 HTTP 協定,是以握手時不容易屏蔽,能通過各種 HTTP 代理伺服器。
(3)資料格式比較輕量,性能開銷小,通信高效。
(4)可以發送文本,也可以發送二進制資料。
(5)沒有同源限制,用戶端可以與任意伺服器通信。
(6)協定辨別符是
(如果加密,則為ws
wss
),伺服器網址就是 URL。
WebSocket 的用法
var ws = new WebSocket("wss://echo.websocket.org"); ws.onopen = function(evt) { console.log("Connection open ..."); ws.send("Hello WebSockets!"); }; ws.onmessage = function(evt) { console.log( "Received Message: " + evt.data); ws.close(); }; ws.onclose = function(evt) { console.log("Connection closed."); };
用戶端的 API
1)WebSocket 構造函數,用于建立 WebSocket 執行個體。執行下面語句之後,用戶端就會與伺服器進行連接配接。
var ws = new WebSocket('ws://localhost:8080');
2)webSocket.readyState
3)webSocket.onopen
4)webSocket.onclose
5)webSocket.onmessage
6)webSocket.send()
7)webSocket.bufferedAmount
8)webSocket.onerror
服務端的實作
常用的 Node 實作有以下三種
µWebSockets
Socket.IO
WebSocket-Node
推薦一款非常特别的 WebSocket 伺服器:Websocketd。
-
浏覽器跨域問題解決(九種跨域方式)
最經典的跨域方案jsonp
最流行的跨域方案cors
最友善的跨域方案nginx反向代理
其它跨域方案:
-
常見web安全及防護
web安全受到的威脅來自于以下幾種攻擊方式:
sql注入,
xss(惡意注入js和網頁元素),
csrf(代替使用者完成互動并通路危險網站)
我們的防護:
1)對使用者輸入内容進行限制和校驗
2)對所有關鍵資料進行加密
3)接口送出方式嚴格規範,資料送出不使用get
-
浏覽器存儲和服務端存儲
cookie和session的差別
1)存儲位置有區分,cookie存在浏覽器緩存中,session存儲在伺服器上
2)存儲大小和數量 cookie小于session
3)保密性 cookie對遊覽器和使用者可見 session存在伺服器上,保密性更佳
4)伺服器壓力 session對伺服器壓力更大
在實際開發過程中,cookie和session都很少使用,更為常用的是token,它比上兩個優勢更大,更好用,安全性高,可擴充性強,多平台跨域,無狀态。可實作,單點登入和多點登入等功能。
不要混淆session和session Storage
session是身份驗證(類似于令牌),session是一次浏覽器和伺服器的互動的會話,當通路伺服器這個網頁的時候,會在伺服器端的記憶體裡開辟一塊記憶體,這塊記憶體就叫做session,而這個記憶體是跟浏覽器關聯在一起的。這個浏覽器指的是浏覽器視窗或浏覽器的子視窗,意思就是,隻允許目前這個session對應的浏覽器通路,就算是在同一個機器上新啟的浏覽器也是無法通路的。而另外一個浏覽器也需要記錄session的話,就會再啟一個屬于自己的session
session Storage是一種存儲方式,資料儲存在浏覽器緩存中,關閉浏覽器和标簽頁就會消失。特别的一點在于,即便是相同域名下的兩個頁面,隻要它們不在同一個浏覽器視窗中打開,那麼它們的 Session Storage 内容便無法共享。
local Storage存儲在本地需要手動删除才會消失,理論上 Cookie 無法勝任的、可以用簡單的鍵值對來存取的資料存儲任務,都可以交給 Local Storage 來做。存儲一些内容穩定的資源。比如圖檔内容豐富的電商網站會用它來存儲 Base64 格式的圖檔字元串,存儲一些不經常更新的 CSS、JS 等靜态資源。
cookie是把少量的資訊存儲在使用者端浏覽器緩存中,它是全局的,在同一個域名下的所有請求,都會攜帶 Cookie。很快速友善。而且它本身存儲的尺寸大小也有限 4k左右,最關鍵是使用者是可見的,并可以随意的修改,很不安全。Cookie 雖然小,請求卻可以有很多,随着請求的疊加,這樣的不必要的 Cookie 帶來的開銷将是無法想象的。靜态資源往往并不需要 Cookie 攜帶什麼認證資訊。把靜态資源和首頁面置于不同的域名下,完美地避免了不必要的 Cookie 的出現!
cookies和localStorage和sessionStorage是同一類,都是儲存方式,都遵循同源政策。隻是大小,儲存位置,儲存時間不一樣 大小 cookies<sessionStorage=localStorage 5-10M 之間
儲存位置 本地
IndexedDB
IndexedDB 是沒有存儲上限的(一般來說不會小于 250M)
IndexedDB 可以看做是 LocalStorage 的一個更新,當資料的複雜度和規模上升到了 LocalStorage 無法解決的程度,我們毫無疑問可以請出 IndexedDB 來幫忙。
-
前端造成記憶體洩漏的操作
1)閉包由于閉包會使得函數中的變量都被儲存在記憶體中,記憶體消耗很大,過多的使用閉包,不及時釋放,會導緻記憶體洩漏。
2)意外全局函數中定義參數,var 定義,會成為全局變量,使用es6的let可以避免這種情況。
3)定時器
4)生命周期中使用全局函數,未釋放
5)echarts
6)keep-alive元件
什麼是記憶體洩漏?
基于垃圾回收機制,當有變量和對象應該被回收而沒有被回收時,一直占用和停留在堆記憶體中,這就産生記憶體洩漏。
記憶體洩漏會導緻記憶體被占用過多無法釋放,進而導緻系統記憶體配置設定不足,造成了記憶體溢出進而導緻應用Crash(浏覽器崩潰)。
還有對于現在電腦來說,一些記憶體洩漏并不影響。
-
性能監控
performance
function getsec(time) { return time / 1000 + 's' } window.onload = function () { var per = window.performance.timing; console.log('DNS查詢耗時' + getsec(per.domainLookupEnd - per.domainLookupStart)) console.log('TCP連結耗時' + getsec(per.connectEnd - per.connectStart)) console.log('request請求響應耗時' + getsec(per.responseEnd - per.responseStart)) console.log('dom渲染耗時' + getsec(per.domComplete - per.domInteractive)) console.log('白屏時間' + getsec(firstPaint - pageStartTime)) console.log('domready可操作時間' + getsec(per.domContentLoadedEventEnd - per.fetchStart)) }