在去年末開始換工做,直到如今算是告了一個段落,斷斷續續的也面試了很多公司,如今回想起來,那段時間經歷了被面試官手撕,被筆試題狂懟,悲傷的時候差點留下沒技術的淚水。javascript
這篇文章我打算把我找工做遇到的各類面試題(每次面試完我都會總結)和我本身複習遇到比較有意思的題目,作一份彙總,年後是跳槽高峯期,也許能幫到一些小夥伴。css
先說下這些題目難度,大部分都是基礎題,由於這段經歷給個人感受就是,無論你面試的是高級仍是初級,基礎的知識必定會問到,甚至會有必定的深度,因此基礎仍是很是重要的。html
我將根據類型分爲幾篇文章來寫:前端
面試總結:javascript 面試點彙總(萬字長文)(已完成) 【強烈你們看看這篇,面試中 js 是大頭】vue
面試總結:nodejs 面試點彙總(已完成)html5
面試總結:瀏覽器相關 面試點彙總(已完成)java
面試總結:css 面試點彙總(已完成)node
面試總結:框架 vue 和工程相關的面試點彙總(已完成)jquery
面試總結:非技術問題彙總(已完成)css3
我會抓緊時間把未完成的總結補全的~
這篇文章是對 瀏覽器
相關的題目作總結,歡迎朋友們先收藏在看。
先看看目錄
全部的性能優化中,緩存是最重要也是最直接有效的,畢竟如今都這麼忙,可等不了網頁轉菊花。
緩存分爲強緩存和協商緩存,看下流程圖
緩存機制相關的字段都是在請求和響應頭上
強緩存,在緩存有效期內,客戶端直接讀取本地資源。
強緩存返回的狀態碼是 200
在 http1.0
中使用,表示資源失效的具體時間點 Expires:Sat, 09 Jun 2018 08:13:56 GMT
,如果訪問器和本地時間不一致,可能就會出現問題,在如今 http1.1中換成了 max-age
,爲了兼容也能夠加上。
指定指令來實現緩存機制,多個指令間逗號分隔,常見的指令有如下幾個,完整的可點擊下文中的 mdn 鏈接查看
max-age
: 強緩存的有效時間,單位秒 max-age=30672000
no-cache
:使用緩存協商,先與服務器確認返回的響應是否被更改。
no-store
:直接禁止遊覽器緩存數據,每次用戶請求該資源,都會向服務器發送一個請求,每次都會下載完整的資源,可用於關閉緩存。
public
:代表響應能夠被任何對象(包括:發送請求的客戶端,代理服務器,等等)緩存,即便是一般不可緩存的內容(例如,該響應沒有max-age指令或Expires消息頭)。
private
:代表響應只能被單個用戶緩存,不能做爲共享緩存(即代理服務器不能緩存它)。私有緩存能夠緩存響應內容。
強緩存,在緩存有效期內,客戶端直接讀取本地資源。
強緩存返回的狀態碼是 200
在 http1.0
中使用,表示資源失效的具體時間點 Expires:Sat, 09 Jun 2018 08:13:56 GMT
,如果訪問器和本地時間不一致,可能就會出現問題,在如今 http1.1中換成了 max-age
,爲了兼容也能夠加上。
協商緩存,關鍵在於協商,在使用本地緩存以前,須要先跟服務器作個對比,服務器告知你的資源可用,是最新的,那就能夠直接取本地資源,反之,服務器返回最新的資源給客戶端,客戶端收到後更新本地資源。
狀態碼:
採用資源最後修改時間來判斷,單位精度秒
Last-Modified:服務器資源的最新更新時間 Tue, 14 Jan 2020 09:18:29 GMT
If-Modified-Since:客戶端發起協商,把本地記錄的文件更新時間傳給服務器,服務器進行判斷比較
這個判斷方式是 http1.0 的產物,由於時間精度是秒,若文件的更新頻率在秒級之內,就會出現文件不一致。
爲了解決上面的那個問題, http1.1 加了這組標記
ETag:服務器根據內容生成惟一的字符串標識
If-None-Match:客戶端發起協商,把本地記錄的 hash 標識傳給服務器,服務器進行判斷比較。
若同時存在 Last-Modified
和 ETag
, ETag
的優先級更高。
可看到有兩個來源:
memory cache
:內存中讀取
disk cache
:硬盤中讀取
內存固然要比硬盤讀取快,爲啥會有存放硬盤呢?
由於內存瀏覽器內存有限啊,因此瀏覽器會有一套機制,根據文件大小何使用頻率存放不一樣的位置,具體的實現取決於瀏覽器廠商,不過這微小對用戶是無感知的。
developer.mozilla.org/zh-CN/docs/…
PWA(Progressive web apps,漸進式 Web 應用)運用現代的 Web API 以及傳統的漸進式加強策略來建立跨平臺 Web 應用程序。(來自 MDN)
先看看 PWA 有哪些核心技術,就知道它有哪些優點了
App Shell 架構是構建 Progressive Web App 的一種方式,這種應用能可靠且即時地加載到您的用戶屏幕上,與本機應用類似。
這個模型包含界面所須要的最小資源文件,若是離線緩存,能夠確保重複訪問都有快速響應的特性,頁面可快速渲染,網絡僅僅獲取數據。
或者這麼理解, App Shell 就相似於原生app,沒網絡也能夠本地啓動。
PWA 的核心,上面說到緩存可讓頁面儘快加載,但必須有網絡的狀況下才行,沒網絡下還想加載網頁咋辦?
ServiceWork 持久的離線緩存的能力就能夠實現。
Service Worker 有如下功能和特性:
一個獨立的 worker 線程,獨立於當前網頁進程,有本身獨立的 worker context
一旦被 install,就永遠存在,除非被手動 unregister
用到的時候能夠直接喚醒,不用的時候自動睡眠
可編程攔截代理請求和返回,緩存文件,緩存的文件能夠被網頁進程取到(包括網絡離線狀態)
離線內容開發者可控
能向客戶端推送消息
不能直接操做 DOM
必須在 HTTPS 環境下才能工做
異步實現,內部大都是經過 Promise 實現
js 是單線程的,ServiceWork 獨立線程意味着不會阻塞js執行;可編程攔截代理請求和返回,可自定義文件緩存策略。
這些特色意味着開發者有足夠的權限去操做緩存,讓緩存作到優雅,效率達到極致
接下來核心是如何讓設計緩存策略,
推薦你們看看開源的 wordbox 封裝的緩存策略,策略更加豐富。
代碼不復雜,主要是聲明週期、與js線程間通訊、api調用,就不貼上來了。
參考文檔:
developer.mozilla.org/zh-CN/docs/…
這是一個大體的流程,面試官會從中挑出其餘點來接着問
先看這圖,html文檔 和 css 渲染過程的圖
頁面是採用流式佈局來繪製,左到右,上到下,那麼一個節點的空間屬性如果發生了變化,那麼會影響到其餘節點的空間佈局,須要從新收集節點信息,在進行繪製,這就是迴流的過程。
重繪指的是對元素的外觀作處理,好比顏色、背景、陰影等。
因此迴流必定觸發重繪。
獲取位置信息或者修改幾何屬性,以下:
// 獲取位置信息相關屬性 - offsetTop offsetLeft offsetWidth offsetHeight 相對於父級容器的偏移量 - scrollTop scrollLeft scrollWidth scrollHeight 相對於父級容器滾動上去的距離 - clientTop clientLeft clientWidth clientHeight 元素邊框的厚度 - getComputedStyle() - getBoundingClientRect 複製代碼
對樹的局部甚至全局從新生成是很是耗性能的,因此要避免頻繁觸發迴流
開啓後,會將 dom 元素提高爲獨立的渲染層,它的變化不會再影響文檔流中的佈局。
http 是創建在 TCP 上的應用層協議,超文本傳送協議。
是單向的短連接,目前有 http1.0 http 1.1 http2.0
http1.0 :客戶端的每次請求都要求創建一次單獨的鏈接,在處理完本次請求後,就自動釋放鏈接。 http1.1 :能夠在一次鏈接中處理多個請求,而且多個請求能夠重疊進行,不須要等待一個請求結束後再發送下一個請求 http2.0 :可支持多路複用,一個 tcp 可同時傳輸多個 http 請求,頭部數據還作了壓縮
面試官問這個通常是更關注對 tcp 的理解
tcp 是傳輸層協議,它的特色是:三次握手和四次揮手。
三次握手的目的是爲了防止已經失效的鏈接請求報文段忽然又傳到服務端,而產生錯誤,因此要創建可靠的鏈接發送數據
三次握手創建鏈接過程:
四次揮手斷開鏈接的過程:
傳輸層的另一個協議 UDP 稱爲用戶數據報協議,無鏈接的傳輸協議。
UDP 是報文的搬運工,不須要創建徹底可靠的連接,不保證數據的可靠性,由於協議控制項比較少,且報文頭部簡單,報文體積相對要小,速度上相比更快,實時性更高,好比電話會議、多媒體數據流等場景就採用 UDP
http 報文傳輸過程當中是明文的,能夠經過抓包的方式看到報文內容,這就暴露一個安全問題,易被劫持篡改。
爲了解決這個問題,就有了 TLS ,https = http + TLS
TLS:安全傳輸層協議,用於在兩個通訊應用程序之間提供保密性和數據完整性,該協議由兩層組成: TLS 記錄協議(TLS Record)和 TLS 握手協議(TLS Handshake)。
TLS 利用非對稱加密演算來對通訊方作身份認證,以後交換對稱密鑰做爲會談密鑰(Session key),所以 https 分爲兩個階段
步驟以下:
對前端來講,畢竟偏向於理論,因此建議你們根據步驟畫一畫流程圖,更利於理解記憶。
上面第一步講到 CA證書,假如沒有證書驗證這一環節,那麼公鑰在傳輸過程極有可能被中間人攔截,來個狸貓換太子,將服務端的公鑰換成它本身的公鑰,返回給客戶端,這麼一來,就徹底起不到加密的做用了,也就是中間人攻擊。
因此就須要一個驗證的機制,保證公鑰是來自服務端的,沒有被篡改的,CA證書就出場了。
CA證書,是由 CA 機構頒發的一個憑證,裏面關鍵的信息有,簽名算法、簽名hash算法、頒發者、有效期、公鑰、指紋,這個兩個算法就表示對稱階段和非對稱階段採用的算法,公鑰就是服務端的公鑰,在申請的時候,企業須要上傳公鑰給CA機構,重點是這個指紋,這個指紋是由 CA 機構經過私鑰對一段簽名加密生成的。
因此經過驗證證書是否合法,就知道公鑰是否被篡改,那麼怎麼驗證合法呢?
天然是經過證書的指紋。
在瀏覽器和我的PC中,都預裝了頂級的 CA 機構證書和公鑰,因此瀏覽器獲取到證書後,經過內置的公鑰對指紋進行解密獲得簽名,而後瀏覽器也根據一樣的規則生成一段簽名,兩段簽名進行比較,驗證經過,那麼這個證書中公鑰就是可信的。
那麼這樣一來是否是就能夠徹底避免了中間人攻擊呢?
畢竟頂級的 CA 證書是內置的,仍是有一種方式,你們是否還記得咱們用,咱們是能夠用 Fiddle 對 https 進行抓包的,那 Fiddle 算不算中間人呢 ?
Fiddle 之因此能攔截成功是由於,咱們在抓包以前,在咱們本身手機安裝一份來自 Fiddle 的證書,也就是客戶端本身信任了第三方來源的證書,這麼一來客戶端天然能解析出 Fiddle 轉發出來的報文啦。
因此只要不隨意信任第三方證書,基本上是不會發生中間人攻擊的。
options 一般用於,在跨域請求前發起預檢請求,以檢測請求是否被服務器接受。
跨域請求中分爲簡單請求和預檢請求兩種,符合如下條件可視爲簡單請求:
GET POST HEAD
text/plain mutipart/form-data application/x-www-form-urlencode
三種之一- Accept
- Accept-Language
- Content-Language
- Content-Type (須要注意額外的限制)
- DPR
- Downlink
- Save-Data
- Viewport-Width
- Width
複製代碼
除去簡單請求外,其餘請求就會先觸發預檢請求。
常見的,好比使用
預檢請求返回的頭部報文中有
Access-Control-Allow-Origin
: 服務器可接受的請求來源
Access-Control-Request-Method
: 服務器實際請求所使用的 HTTP 方法
Access-Control-Request-Headers
: 服務器實際請求所攜帶的自定義首部字段。
客戶端基於從預檢請求得到的信息來判斷,是否繼續執行跨域請求。
注意:跨域請求若想發送 cookie 信息,須要服務端設置 resp.setHeader("Access-Control-Allow-Credentials","true"); 客戶端設置 withCredentials: true
參考資料: cloud.tencent.com/developer/n…
直接看圖
Content-Type 字段來獲知請求中的消息主體是用何種方式編碼
Content-Type: application/json : json 字符串 Content-Type: application/x-www-form-urlencoded : & 將
key=value
進行拼接, jquery 默認使用這個 Content-Type: multipart/form-data : 經常使用於文件上傳
主要有兩類 XSS
CSRF
跨站腳本攻擊,攻擊者將一段可執行的代碼注入到網頁中,如連接、輸入框,分爲持久形和臨時性的,持久性的是惡意代碼被存儲到數據庫裏,會形成持久的攻擊;臨時性的是僅在當前被工具頁面上生效;
防範的方式是對與網頁上獲取的內容要作轉義處理。
跨站請求僞造,構造一個釣魚網站,利用站點對瀏覽器的信任,從而欺騙用戶,發起請求進行惡意操做。
用戶在瀏覽器登陸後,站點是信任瀏覽器的,但瀏覽器是無法知道請求是不是用戶自願發起的,站點信任後,所發起的請求瀏覽器都是信任的。
那麼用戶是已登陸的狀況下,釣魚站點中發起跨域請求,跨域標籤或者 form 表單,就會把用戶的認證信息 cookies 帶上,從而到達僞造用戶身份進行攻擊。
防範方式:
關於 xss csrf 網上有很詳細的介紹,不過核心原理仍是比較簡單的。
第一次聽到有點懵,由於是 CORS ,回來查了資料才明白。
CORB 是一種判斷是否要在跨站資源數據到達頁面以前阻斷其到達當前站點進程中的算法,下降了敏感數據暴露的風險。是站點隔離的一種實現機制,針對跨域標籤,保護站點資源。
當跨域請求回來的數據 MIME type
同跨域標籤應有的 MIME
類型不匹配時,瀏覽器會啓動 CORB
保護數據不被泄漏,被保護的數據類型只有 html xml json
。
MIME 是一個互聯網標準,擴展了電子郵件標準,使其能夠支持更多的消息類型。常見 MIME 類型如:text/html text/plain image/png application/javascript ,用於標識返回消息屬於哪種文檔類型。寫法爲 type/subtype。 在 HTTP 請求的響應頭中,以 Content-Type: application/javascript; charset=UTF-8 的形式出現,MIME type 是 Content-Type 值的一部分
這篇文章寫的很是詳細,建議你們直接查看 Cross-Origin Read Blocking (CORB)
主流的有一下幾種
image script
發起 get 方法的跨域請求var img = new Image; img.onload = function() { }, img.onerror = function() { }, img.src = options.url; 複製代碼
application/javascript
的方式進行解析,就能夠觸發預設好的回調函數。/* html */ let scr = document.createElement('script'); scr.src = `http://127.0.0.1:3500/xx?callback=cb` document.getElementsByTagName('head')[0].appendChild(scr) function cb(res){ console.log('into'); console.log(res); } /* server */ let data = { name: 'xiaoli' } var str = ctx.query.callback + '(' + JSON.stringify(data) + ')'; // ctx.query = {callback:'cb'} // str = 'cb({"name":"xiaoli"})' ctx.body = str; 複製代碼
經常使用 nginx 作反向代理,詳細配置就很少說了
這就全是服務端的工做了,主要的三個參數
Access-Control-Allow-Origin
: 服務器可接受的請求來源
Access-Control-Request-Method
: 服務器實際請求所使用的 HTTP 方法
Access-Control-Request-Headers
: 服務器實際請求所攜帶的自定義首部字段。
假若有 BFF 層的話,能夠在這一層作一箇中轉,這個就得看項目架構是否有條件了。
html 的 meta 設置的緩存策略是對於當前文檔有效,用於定義頁面緩存。
與http的請求參數很相像,就不重複了,詳細介紹可參考 設置meta標籤 清除頁面緩存
hash 路由,在 html5 前,爲了解決單頁路由跳轉問題採用的方案, hash 的變化不會觸發頁面渲染,服務端也沒法獲取到 hash 值,前端可經過監聽 hashchange
事件來處理hash值的變化
window.addEventListener('hashchange', function(){ // 監聽hash變化,點擊瀏覽器的前進後退會觸發 }) 複製代碼
history 路由,是 html5 的規範,提供了對history棧中內容的操做,經常使用api有:
window.history.pushState(state, title, url) // let currentState = history.state; 獲取當前state // state:須要保存的數據,這個數據在觸發popstate事件時,能夠在event.state裏獲取 // title:標題,基本沒用,通常傳 null // url:設定新的歷史記錄的 url。新的 url 與當前 url 的 origin 必須是一樣的,不然會拋出錯誤。url能夠是絕對路徑,也能夠是相對路徑。 //如 當前url是 https://www.baidu.com/a/,執行history.pushState(null, null, './qq/'),則變成 https://www.baidu.com/a/qq/, //執行history.pushState(null, null, '/qq/'),則變成 https://www.baidu.com/qq/ window.history.replaceState(state, title, url) // 與 pushState 基本相同,但她是修改當前歷史記錄,而 pushState 是建立新的歷史記錄 window.addEventListener("popstate", function() { // 監聽瀏覽器前進後退事件,pushState 與 replaceState 方法不會觸發 }); 複製代碼
<div class="an" onclick="aa()">aaaa</div>
document.getElementById("demo").οnclick=function(){}
document.addEventListener('name',()=>{})
瀏覽器中的事件觸發有三個階段:
事件委託也叫事件代理,在 dom 節點中,由於有事件冒泡機制,因此子節點的事件能夠被父節點捕獲。
所以,在適當的場景下將子節點的事件用父節點監聽處理,支持的事件 點擊事件 鼠標事件監聽。
事件代理的優點:
關於事件捕獲和事件冒泡的理解:
事件捕獲:事件從外往裏傳播,addEventListener 最後一個參數設置成 true 就能夠捕獲事件,默認是 false ,監聽事件冒泡。捕獲是計算機處理輸入的邏輯
事件冒泡:事件由內往外傳播,冒泡是人類理解事件的思惟。
target:指的是事件流的目標階段,獲取的是被點擊的元素。
currentTarget:在事件流的捕獲和冒泡階段時,是指向當前事件活動對象,只有在目標階段的時候,二者纔會相等
根據頁面渲染流程可得知:
都是告知瀏覽器提早加載文件(圖片、視頻、js、css等),但執行上是有區別的。
prefetch
:其利用瀏覽器空閒時間來下載或預取用戶在不久的未來可能訪問的文檔。<link href="/js/xx.js" rel="prefetch">
preload
: 能夠指明哪些資源是在頁面加載完成後即刻須要的,瀏覽器在主渲染機制介入前就進行預加載,這一機制使得資源能夠更早的獲得加載並可用,且更不易阻塞頁面的初步渲染,進而提高性能。 <link href="/js/xxx.js" rel="preload" as="script">
須要 as 指定資源類型,目前可用的屬性類型有以下:
audio: 音頻文件。
document: 一個將要被嵌入到<frame>或<iframe>內部的HTML文檔。
embed: 一個將要被嵌入到<embed>元素內部的資源。
fetch: 那些將要經過fetch和XHR請求來獲取的資源,好比一個ArrayBuffer或JSON文件。
font: 字體文件。
image: 圖片文件。
object: 一個將會被嵌入到<embed>元素內的文件。
script: JavaScript文件。
style: 樣式表。
track: WebVTT文件。
worker: 一個JavaScript的web worker或shared worker。
video: 視頻文件。
複製代碼
用於js腳本預加載
async
: 加載腳本和渲染後續文檔元素並行進行,腳本加載完成後,暫停html解析,當即解析js腳本
defer
: 加載腳本和渲染後續文檔元素並行進行,但腳本的執行會等到 html 解析完成後執行
參考資料:
developer.mozilla.org/zh-CN/docs/…
developer.mozilla.org/zh-CN/docs/…
<meta name="viewport" content="width=500, initial-scale=1">
這裏只指定了兩個屬性,寬度和縮放,實際上 viewport 能控制的更多,它能表示的所有屬性以下:
由於在之前移動端雙擊能夠縮放或者滑動,因此爲了區分是點擊仍是雙擊,加了 300ms 的延遲。
解決方案:
(後續再補上)
使用 performance.timing
這個api就能夠獲取到絕大部分性能相關的數據
navigationStart
:在同一個瀏覽器上下文中,前一個網頁(與當前頁面不必定同域)unload 的時間戳,若是無前一個網頁 unload ,則與 fetchStart 值相等unloadEventStart
:前一個網頁(與當前頁面同域)unload 的時間戳,若是無前一個網頁 unload 或者前一個網頁與當前頁面不一樣域,則值爲 0redirectStart
:第一個 HTTP 重定向發生時的時間。有跳轉且是同域名內的重定向纔算,不然值爲 0redirectEnd
:最後一個 HTTP 重定向完成時的時間。有跳轉且是同域名內的重定向纔算,不然值爲 0fetchStart
:瀏覽器準備好使用 HTTP 請求抓取文檔的時間,這發生在檢查本地緩存以前domainLookupStart
:DNS 域名查詢開始的時間,若是使用了本地緩存(即無 DNS 查詢)或持久鏈接,則與 fetchStart 值相等domainLookupEnd
:DNS 域名查詢完成的時間,若是使用了本地緩存(即無 DNS 查詢)或持久鏈接,則與 fetchStart 值相等connectStart
:HTTP(TCP) 開始創建鏈接的時間,若是是持久鏈接,則與 fetchStart 值相等,若是在傳輸層發生了錯誤且從新創建鏈接,則這裏顯示的是新創建的鏈接開始的時間secureConnectionStart
:HTTPS 鏈接開始的時間,若是不是安全鏈接,則值爲 0connectEnd
:HTTP(TCP) 完成創建鏈接的時間(完成握手),若是是持久鏈接,則與 fetchStart 值相等,若是在傳輸層發生了錯誤且從新創建鏈接,則這裏顯示的是新創建的鏈接完成的時間requestStart
:HTTP 請求讀取真實文檔開始的時間(完成創建鏈接),包括從本地讀取緩存,鏈接錯誤重連時,這裏顯示的也是新創建鏈接的時間responseStart
:HTTP 開始接收響應的時間(獲取到第一個字節),包括從本地讀取緩存responseEnd
:HTTP 響應所有接收完成的時間(獲取到最後一個字節),包括從本地讀取緩存domLoading
:開始解析渲染 DOM 樹的時間,此時 Document.readyState 變爲 loading,並將拋出 readystatechange 相關事件domInteractive
:完成解析 DOM 樹的時間,Document.readyState 變爲 interactive,並將拋出 readystatechange 相關事件domContentLoadedEventStart
:DOM 解析完成後,網頁內資源加載開始的時間,表明DOMContentLoaded事件觸發的時間節點domContentLoadedEventEnd
:DOM 解析完成後,網頁內資源加載完成的時間(如 JS 腳本加載執行完畢),文檔的DOMContentLoaded 事件的結束時間,也就是jQuery中的domready時間;domComplete
:DOM 樹解析完成,且資源也準備就緒的時間,Document.readyState 變爲 complete,並將拋出 readystatechange 相關事件loadEventStart
:load 事件發送給文檔,也即 load 回調函數開始執行的時間,若是沒有綁定 load 事件,值爲 0loadEventEnd
:load 事件的回調函數執行完畢的時間,若是沒有綁定 load 事件,值爲 0DNS查詢耗時 = domainLookupEnd - domainLookupStart
TCP連接耗時 = connectEnd - connectStart
request請求耗時 = responseEnd - responseStart
解析dom樹耗時 = domComplete - domInteractive
白屏時間 = domloadng - fetchStart
domready時間 = domContentLoadedEventEnd - fetchStart
onload時間 = loadEventEnd - fetchStart
這個題有點無聊了,但仍是遇到了
輸入框對於輸入連續中文的時候可使用如下兩個監聽事件(第一次知道還有這個事件):
compositionstart:事件觸發於一段文字的輸入以前(相似於 keydown 事件,可是該事件僅在若干可見字符的輸入以前,而這些可見字符的輸入可能須要一連串的鍵盤操做、語音識別或者點擊輸入法的備選詞)。
compositionend:當文本段落的組成完成或取消時,事件將被觸發 (具備特殊字符的觸發, 須要一系列鍵和其餘輸入, 如語音識別或移動中的字詞建議)。