2022前端面试题上岸手册-浏览器部分
1. 什么是 XSS 攻擊?
(1)概念
XSS 攻擊指的是跨站腳本攻擊,是一種代碼注入攻擊。攻擊者通過在 網站注入惡意腳本,使之在用戶的瀏覽器上運行,從而盜取用戶的信 息如 cookie 等。
XSS 的本質是因為網站沒有對惡意代碼進行過濾,與正常的代碼混合 在一起了,瀏覽器沒有辦法分辨哪些腳本是可信的,從而導致了惡意 代碼的執行。
攻擊者可以通過這種攻擊方式可以進行以下操作: 獲取頁面的數據,如 DOM、cookie、localStorage;
DOS 攻擊,發送合理請求,占用服務器資源,從而使用戶無法訪問服 務器;
破壞頁面結構;?
流量劫持(將連接指向某網站)
(2)攻擊類型
XSS 可以分為存儲型、反射型和 DOM 型:
存儲型指的是惡意腳本會存儲在目標服務器上,當瀏覽器請求數據時, 腳本從服務器傳回并執行。
反射型指的是攻擊者誘導用戶訪問一個帶有惡意代碼的 URL 后,服 務器端接收數據后處理,然后把帶有惡意代碼的數據發送到瀏覽器端, 瀏覽器端解析這段帶有 XSS 代碼的數據后當做腳本執行,最終完成 XSS 攻擊。
DOM 型指的通過修改頁面的 DOM 節點形成的 XSS。
1)存儲型 XSS 的攻擊步驟:
1.攻擊者將惡意代碼提交到目標網站的數據庫中。 2.用戶打開目標網站時,網站服務端將惡意代碼從數據庫取出,拼接
在 HTML 中返回給瀏覽器。 3.用戶瀏覽器接收到響應后解析執行,混在其中的惡意代碼也被執行。
4.惡意代碼竊取用戶數據并發送到攻擊者的網站,或者冒充用戶的行 為,調用目標網站接口執行攻擊者指定的操作。
這種攻擊常?于帶有用戶保存數據的網站功能,如論壇發帖、商品評 論、用戶私信等。
2)反射型 XSS 的攻擊步驟: 1.攻擊者構造出特殊的 URL,其中包含惡意代碼。
2.用戶打開帶有惡意代碼的 URL 時,網站服務端將惡意代碼從 URL 中取出,拼接在 HTML 中返回給瀏覽器。
3.用戶瀏覽器接收到響應后解析執行,混在其中的惡意代碼也被執行。 4.惡意代碼竊取用戶數據并發送到攻擊者的網站,或者冒充用戶的行
為,調用目標網站接口執行攻擊者指定的操作。
反射型 XSS 跟存儲型 XSS 的區別是:存儲型 XSS 的惡意代碼存在
數據庫里,反射型 XSS 的惡意代碼存在 URL 里。
反射型 XSS 漏洞常?于通過 URL 傳遞參數的功能,如網站搜索、跳 轉等。 由于需要用戶主動打開惡意的 URL 才能生效,攻擊者往往會 結合多種手段誘導用戶點擊。
3)DOM 型 XSS 的攻擊步驟: 1.攻擊者構造出特殊的 URL,其中包含惡意代碼
2.用戶打開帶有惡意代碼的 URL。 3.用戶瀏覽器接收到響應后解析執行,前端 JavaScript 取出 URL
中的惡意代碼并執行。 4.惡意代碼竊取用戶數據并發送到攻擊者的網站,或者冒充用戶的行
為,調用目標網站接口執行攻擊者指定的操作。
DOM 型 XSS 跟前兩種 XSS 的區別:DOM 型 XSS 攻擊中,取出和執 行惡意代碼由瀏覽器端完成,屬于前端JavaScript 自身的安全漏洞, 而其他兩種 XSS 都屬于服務端的安全漏洞。
2. 如何防御 XSS 攻擊?
可以看到 XSS 危害如此之大, 那么在開發網站時就要做好防御措施, 具體措施如下:
可以從瀏覽器的執行來進行預防,一種是使用純前端的方式,不用服 務器端拼接后返回(不使用服務端渲染)。另一種是對需要插入到 HTML 中的代碼做好充分的轉義。對于 DOM 型的攻擊,主要是前端腳 本的不可靠而造成的,對于數據獲取渲染和字符串拼接的時候應該對 可能出現的惡意代碼情況進行判斷。
使用 CSP ,CSP 的本質是建立一個白名單,告訴瀏覽器哪些外部資 源可以加載和執行,從而防止惡意代碼的注入攻擊。
1.CSP 指的是內容安全策略,它的本質是建立一個白名單,告訴瀏覽 器哪些外部資源可以加載和執行。我們只需要配置規則,如何攔截由 瀏覽器自己來實現。
2.通常有兩種方式來開啟 CSP,一種是設置 HTTP 首部中的 Content-Security-Policy,一種是設置 meta 標簽的方式 <meta http-equiv="Content-Security-Policy">
對一些敏感信息進行保護,比如 cookie 使用 http-only,使得腳本 無法獲取。也可以使用驗證碼,避免腳本偽裝成用戶執行一些操作。
3. 什么是 CSRF 攻擊?
(1)概念
CSRF 攻擊指的是跨站請求偽造攻擊,攻擊者誘導用戶進入一個第三 方網站,然后該網站向被攻擊網站發送跨站請求。如果用戶在被攻擊 網站中保存了登錄狀態,那么攻擊者就可以利用這個登錄狀態,繞過 后臺的用戶驗證,冒充用戶向服務器執行一些操作。
CSRF 攻擊的本質是利用 cookie 會在同源請求中攜帶發送給服務器 的特點,以此來實現用戶的冒充。
(2)攻擊類型
常見的 CSRF 攻擊有三種:
GET 類型的 CSRF 攻擊,比如在網站中的一個 img 標簽里構建一個 請求,當用戶打開這個網站的時候就會自動發起提交。
POST 類型的 CSRF 攻擊,比如構建一個表單,然后隱藏它,當用戶 進入頁面時,自動提交這個表單。
鏈接類型的 CSRF 攻擊,比如在 a 標簽的 href 屬性里構建一個請 求,然后誘導用戶去點擊。
4. 如何防御 CSRF 攻擊?
CSRF 攻擊可以使用以下方法來防護:
進行同源檢測,服務器根據 http 請求頭中 origin 或者 referer 信息來判斷請求是否為允許訪問的站點,從而對請求進行過濾。當 origin 或者 referer 信息都不存在的時候,直接阻止請求。這種方 式的缺點是有些情況下 referer 可以被偽造,同時還會把搜索引擎 的鏈接也給屏蔽了。所以一般網站會允許搜索引擎的頁面請求,但是 相應的頁面請求這種請求方式也可能被攻擊者給利用。(Referer 字 段會告訴服務器該網頁是從哪個頁面鏈接過來的)
使用 CSRF Token 進行驗證,服務器向用戶返回一個隨機數 Token , 當網站再次發起請求時,在請求參數中加入服務器端返回的 token , 然后服務器對這個 token 進行驗證。這種方法解決了使用 cookie 單一驗證方式時,可能會被冒用的問題,但是這種方法存在一個缺點 就是,我們需要給網站中的所有請求都添加上這個 token,操作比較 繁瑣。還有一個問題是一般不會只有一臺網站服務器,如果請求經過 負載平衡轉移到了其他的服務器,但是這個服務器的 session 中沒 有保留這個 token 的話,就沒有辦法驗證了。這種情況可以通過改 變 token 的構建方式來解決。
對 Cookie 進行雙重驗證,服務器在用戶訪問網站頁面時,向請求域 名注入一個 Cookie,內容為隨機字符串,然后當用戶再次向服務器 發送請求的時候,從 cookie 中取出這個字符串,添加到 URL 參數 中,然后服務器通過對 cookie 中的數據和參數中的數據進行比較, 來進行驗證。使用這種方式是利用了攻擊者只能利用 cookie,但是 不能訪問獲取 cookie 的特點。并且這種方法比 CSRF Token 的方法 更加方便,并且不涉及到分布式訪問的問題。這種方法的缺點是如果 網站存在 XSS 漏洞的,那么這種方式會失效。同時這種方式不能做 到子域名的隔離。
在設置 cookie 屬性的時候設置 Samesite ,限制 cookie 不能作為 被第三方使用,從而可以避免被攻擊者利用。Samesite 一共有兩種 模式,一種是嚴格模式,在嚴格模式下 cookie 在任何情況下都不可 能作為第三方 Cookie 使用,在寬松模式下,cookie 可以被請求是 GET 請求,且會發生頁面跳轉的請求所使用。
5. 有哪些可能引起前端安全的問題?
跨站腳本 (Cross-Site Scripting, XSS): 一種代碼注入方式, 為了 與 CSS 區分所以被稱作 XSS。早期常?于網絡論壇, 起因是網站沒 有對用戶的輸入進行嚴格的限制, 使得攻擊者可以將腳本上傳到帖 子讓其他人瀏覽到有惡意腳本的?面, 其注入方式很簡單包括但不 限于 JavaScript / CSS / Flash 等;
iframe 的濫用: iframe 中的內容是由第三方來提供的,默認情況下 他們不受控制,他們可以在 iframe 中運行JavaScirpt 腳本、Flash 插件、彈出對話框等等,這可能會破壞前端用戶體驗;
跨站點請求偽造(Cross-Site Request Forgeries,CSRF): 指攻擊 者通過設置好的陷阱,強制對已完成認證的用戶進行非預期的個人信 息或設定信息等某些狀態更新,屬于被動攻擊
惡意第三方庫: 無論是后端服務器應用還是前端應用開發,絕大多數 時候都是在借助開發框架和各種類庫進行快速開發,一旦第三方庫被 植入惡意代碼很容易引起安全問題。
6. 網絡劫持有哪幾種,如何防范?
網絡劫持分為兩種:
(1)DNS 劫持: (輸入京東被強制跳轉到淘寶這就屬于 dns 劫持)
DNS 強制解析: 通過修改運營商的本地 DNS 記錄,來引導用戶流量到 緩存服務器
302 跳轉的方式: 通過監控網絡出口的流量,分析判斷哪些內容是可 以進行劫持處理的,再對劫持的內存發起 302 跳轉的回復,引導用戶 獲取內容
(2)HTTP 劫持: (訪問谷歌但是一直有貪玩藍月的廣告),由于 http 明文傳輸,運營商會修改你的 http 響應內容(即加廣告)
(3)DNS 劫持由于涉嫌違法,已經被監管起來,現在很少會有 DNS 劫持,而http 劫持依然非常盛行,最有效的辦法就是全站 HTTPS,將 HTTP 加密,這使得運營商無法獲取明文,就無法劫持你的響應內容。
7. 瀏覽器渲染進程的線程有哪些?
瀏覽器的渲染進程的線程總共有五種
?(1)GUI 渲染線程
負責渲染瀏覽器頁面,解析 HTML、CSS,構建 DOM 樹、構建 CSSOM 樹、 構建渲染樹和繪制頁面;當界面需要重繪或由于某種操作引發回流時, 該線程就會執行。
注意:GUI 渲染線程和 JS 引擎線程是互斥的,當 JS 引擎執行時 GUI 線程會被掛起,GUI 更新會被保存在一個隊列中等到 JS 引擎空閑時 立即被執行。
(2)JS 引擎線程
JS 引擎線程也稱為 JS 內核,負責處理 Javascript 腳本程序,解析 Javascript 腳本,運行代碼;JS 引擎線程一直等待著任務隊列中任 務的到來,然后加以處理,一個 Tab 頁中無論什么時候都只有一個 JS 引擎線程在運行 JS 程序;
注意:GUI 渲染線程與 JS 引擎線程的互斥關系,所以如果 JS 執行的 時間過長,會造成頁面的渲染不連貫,導致頁面渲染加載阻塞。
(3)時間觸發線程
時間觸發線程屬于瀏覽器而不是 JS 引擎,用來控制事件循環;當 JS 引擎執行代碼塊如 setTimeOut 時(也可是來自瀏覽器內核的其他線 程,如鼠標點擊、AJAX 異步請求等),會將對應任務添加到事件觸發 線程中;當對應的事件符合觸發條件被觸發時,該線程會把事件添加 到待處理隊列的隊尾,等待 JS 引擎的處理;
注意:由于 JS 的單線程關系,所以這些待處理隊列中的事件都得排 隊等待 JS 引擎處理(當 JS 引擎空閑時才會去執行);
(4)定時器觸發進程
定時器觸發進程即 setInterval 與 setTimeout 所在線程;瀏覽器定 時計數器并不是由 JS 引擎計數的,因為 JS 引擎是單線程的,如果處 于阻塞線程狀態就會影響記計時的準確性;因此使用單獨線程來計時 并觸發定時器,計時完畢后,添加到事件隊列中,等待 JS 引擎空閑 后執行,所以定時器中的任務在設定的時間點不一定能夠準時執行, 定時器只是在指定時間點將任務添加到事件隊列中;
注意:W3C 在 HTML 標準中規定,定時器的定時時間不能小于 4ms,如 果是小于 4ms,則默認為 4ms。
(5)異步 http 請求線程
XMLHttpRequest 連接后通過瀏覽器新開一個線程請求;
檢測到狀態變更時,如果設置有回調函數,異步線程就產生狀態變更 事件,將回調函數放入事件隊列中,等待 JS 引擎空閑后執行;
8. 僵尸進程和孤兒進程是什么?
孤兒進程:父進程退出了,而它的一個或多個進程還在運行,那這些 子進程都會成為孤兒進程。孤兒進程將被 init 進程(進程號為 1)所 收養,并由 init 進程對它們完成狀態收集工作。
僵尸進程:子進程比父進程先結束,而父進程又沒有釋放子進程占用 的資源,那么子進程的進程描述符仍然保存在系統中,這種進程稱之 為僵死進程。
9. 如何實現瀏覽器內多個標簽頁之間的通信?
實現多個標簽頁之間的通信,本質上都是通過中介者模式來實現的。 因為標簽頁之間沒有辦法直接通信,因此我們可以找一個中介者,讓標簽頁和中介者進行通信,然后讓這個中介者來進行消息的轉發。通 信方法如下:
使用 websocket 協議,因為 websocket 協議可以實現服務器推送, 所以服務器就可以用來當做這個中介者。標簽頁通過向服務器發送數 據,然后由服務器向其他標簽頁推送轉發。
使用 ShareWorker 的方式,shareWorker 會在頁面存在的生命周期 內創建一個唯一的線程,并且開啟多個頁面也只會使用同一個線程。 這個時候共享線程就可以充當中介者的角色。標簽頁間通過共享一個 線程,然后通過這個共享的線程來實現數據的交換。
使用localStorage 的方式,我們可以在一個標簽頁對 localStorage 的變化事件進行監聽,然后當另一個標簽頁修改數據的時候,我們就 可以通過這個監聽事件來獲取到數據。這個時候 localStorage 對象 就是充當的中介者的角色。
使用 postMessage 方法,如果我們能夠獲得對應標簽頁的引用,就 可以使用 postMessage 方法,進行通信。
10. 對瀏覽器的緩存機制的理解
瀏覽器緩存的全過程:
瀏覽器第一次加載資源,服務器返回 200,瀏覽器從服務器下載資源 文件,并緩存資源文件與 response header,以供下次加載時對比使 用;
下一次加載資源時,由于強制緩存優先級較高,先比較當前時間與上 一次返回 200 時的時間差,如果沒有超過 cache-control 設置的 max-age,則沒有過期,并命中強緩存,直接從本地讀取資源。如果 瀏覽器不支持 HTTP1.1,則使用 expires 頭判斷是否過期;
如果資源已過期,則表明強制緩存沒有被命中,則開始協商緩存,向 服務器發送帶有 If-None-Match 和 If-Modified-Since 的請求;
服務器收到請求后,優先根據 Etag 的值判斷被請求的文件有沒有做 修改,Etag 值一致則沒有修改,命中協商緩存,返回 304;如果不 一致則有改動,直接返回新的資源文件帶上新的 Etag 值并返回 200;
如果服務器收到的請求沒有 Etag 值,則將 If-Modified-Since 和 被請求文件的最后修改時間做比對,一致則命中協商緩存,返回 304; 不一致則返回新的 last-modified 和文件并返回 200;
?
很多網站的資源后面都加了版本號,這樣做的目的是:每次升級了 JS 或 CSS 文件后,為了防止瀏覽器進行緩存,強制改變版本號,客戶 端瀏覽器就會重新下載新的 JS 或 CSS 文件 ,以保證用戶能夠及時 獲得網站的最新更新。
11. 協商緩存和強緩存的區別
(1)強緩存
使用強緩存策略時,如果緩存資源有效,則直接使用緩存資源,不必 再向服務器發起請求。
強緩存策略可以通過兩種方式來設置,分別是 http 頭信息中的 Expires 屬性和 Cache-Control 屬性
(1)服務器通過在響應頭中添加 Expires 屬性,來指定資源的過期 時間。在過期時間以內,該資源可以被緩存使用,不必再向服務器發 送請求。這個時間是一個絕對時間,它是服務器的時間,因此可能存 在這樣的問題,就是客戶端的時間和服務器端的時間不一致,或者用 戶可以對客戶端時間進行修改的情況,這樣就可能會影響緩存命中的 結果。
(2)Expires 是 http1.0 中的方式,因為它的一些缺點,在 HTTP 1.1 中提出了一個新的頭部屬性就是 Cache-Control 屬性,它提供 了對資源的緩存的更精確的控制。它有很多不同的值,
Cache-Control 可設置的字段:
public:設置了該字段值的資源表示可以被任何對象(包括:發送請 求的客戶端、代理服務器等等)緩存。這個字段值不常用,一般還是 使用 max-age=來精確控制;
private:設置了該字段值的資源只能被用戶瀏覽器緩存,不允許任 何代理服務器緩存。在實際開發當中,對于一些含有用戶信息的 HTML, 通常都要設置這個字段值,避免代理服務器(CDN)緩存;
no-cache:設置了該字段需要先和服務端確認返回的資源是否發生了 變化,如果資源未發生變化,則直接使用緩存好的資源;
no-store:設置了該字段表示禁止任何緩存,每次都會向服務端發起 新的請求,拉取最新的資源;
max-age=:設置緩存的最大有效期,單位為秒;
s-maxage=:優先級高于 max-age=,僅適用于共享緩存(CDN),優先 級高于 max-age 或者 Expires 頭;
max-stale[=]:設置了該字段表明客戶端愿意接收已經過期的資源, 但是不能超過給定的時間限制。
一般來說只需要設置其中一種方式就可以實現強緩存策略,當兩種方 式一起使用時,Cache-Control 的優先級要高于 Expires。
no-cache 和 no-store 很容易混淆:
no-cache 是指先要和服務器確認是否有資源更新,在進行判斷。也 就是說沒有強緩存,但是會有協商緩存;
no-store 是指不使用任何緩存,每次請求都直接從服務器獲取資源。
(2)協商緩存
如果命中強制緩存,我們無需發起新的請求,直接使用緩存內容,如 果沒有命中強制緩存,如果設置了協商緩存,這個時候協商緩存就會 發揮作用了。
上面已經說到了,命中協商緩存的條件有兩個: max-age=xxx 過期了
值為 no-store
使用協商緩存策略時,會先向服務器發送一個請求,如果資源沒有發 生修改,則返回一個 304 狀態,讓瀏覽器使用本地的緩存副本。如 果資源發生了修改,則返回修改后的資源。
協商緩存也可以通過兩種方式來設置,分別是 http 頭信息中的 Etag 和 Last-Modified 屬性。
(1)服務器通過在響應頭中添加 Last-Modified 屬性來指出資源最 后一次修改的時間,當瀏覽器下一次發起請求時,會在請求頭中添加 一個 If-Modified-Since 的屬性,屬性值為上一次資源返回時的 Last-Modified 的值。當請求發送到服務器后服務器會通過這個屬性 來和資源的最后一次的修改時間來進行比較,以此來判斷資源是否做 了修改。如果資源沒有修改,那么返回 304 狀態,讓客戶端使用本 地的緩存。如果資源已經被修改了,則返回修改后的資源。使用這種 方法有一個缺點,就是 Last-Modified 標注的最后修改時間只能精 確到秒級,如果某些文件在 1 秒鐘以內,被修改多次的話,那么文件 已將改變了但是 Last-Modified 卻沒有改變,這樣會造成緩存命中 的不準確。
(2)因為 Last-Modified 的這種可能發生的不準確性,http 中提 供了另外一種方式,那就是 Etag 屬性。服務器在返回資源的時候, 在頭信息中添加了 Etag 屬性,這個屬性是資源生成的唯一標識符, 當資源發生改變的時候,這個值也會發生改變。在下一次資源請求時, 瀏覽器會在請求頭中添加一個 If-None-Match 屬性,這個屬性的值 就是上次返回的資源的 Etag 的值。服務接收到請求后會根據這個值 來和資源當前的 Etag 的值來進行比較,以此來判斷資源是否發生改 變,是否需要返回資源。通過這種方式,比 Last-Modified 的方式 更加精確。
當 Last-Modified 和 Etag 屬性同時出現的時候,Etag 的優先級更 高。使用協商緩存的時候,服務器需要考慮負載平衡的問題,因此多 個服務器上資源的 Last-Modified 應該保持一致,因為每個服務器上 Etag 的值都不一樣,因此在考慮負載平衡時,最好不要設置 Etag 屬性。
總結:
強緩存策略和協商緩存策略在緩存命中時都會直接使用本地的緩存 副本,區別只在于協商緩存會向服務器發送一次請求。它們緩存不命 中時,都會向服務器發送請求來獲取資源。在實際的緩存機制中,強 緩存策略和協商緩存策略是一起合作使用的。瀏覽器首先會根據請求 的信息判斷,強緩存是否命中,如果命中則直接使用資源。如果不命 中則根據頭信息向服務器發起請求,使用協商緩存,如果協商緩存命 中的話,則服務器不返回資源,瀏覽器直接使用本地資源的副本,如 果協商緩存不命中,則瀏覽器返回最新的資源給瀏覽器。
12. 點擊刷新按鈕或者按 F5、按 Ctrl+F5 (強制刷新)、地址 欄回車有什么區別?
點擊刷新按鈕或者按 F5:瀏覽器直接對本地的緩存文件過期,但是 會帶上 If-Modifed-Since,If-None-Match,這就意味著服務器會對 文件檢查新鮮度,返回結果可能是 304,也有可能是 200。
用戶按 Ctrl+F5(強制刷新):瀏覽器不僅會對本地文件過期,而且 不會帶上 If-Modifed-Since,If-None-Match,相當于之前從來沒有 請求過,返回結果是 200。
地址欄回車: 瀏覽器發起請求,按照正常流程,本地檢查是否過期, 然后服務器檢查新鮮度,最后返回內容。
13. 常見的瀏覽器內核比較
Trident:這種瀏覽器內核是 IE 瀏覽器用的內核,因為在早期 IE 占 有大量的市場份額,所以這種內核比較流行,以前有很多網頁也是根 據這個內核的標準來編寫的,但是實際上這個內核對真正的網頁標準 支持不是很好。但是由于 IE 的高市場占有率,微軟也很長時間沒有 更新 Trident 內核,就導致了 Trident 內核和 W3C 標準脫節。還 有就是 Trident 內核的大量 Bug 等安全問題沒有得到解決,加上一 些專家學者公開自己認為 IE 瀏覽器不安全的觀點,使很多用戶開始 轉向其他瀏覽器。
Gecko:這是 Firefox 和 Flock 所采用的內核,這個內核的優點就 是功能強大、豐富,可以支持很多復雜網頁效果和瀏覽器擴展接口, 但是代價是也顯而易見就是要消耗很多的資源,比如內存。
Presto:Opera 曾經采用的就是 Presto 內核,Presto 內核被稱為 公認的瀏覽網頁速度最快的內核,這得益于它在開發時的天生優勢, 在處理 JS 腳本等腳本語言時,會比其他的內核快 3 倍左右,缺點就 是為了達到很快的速度而丟掉了一部分網頁兼容性。
Webkit:Webkit 是 Safari 采用的內核,它的優點就是網頁瀏覽速 度較快,雖然不及 Presto 但是也勝于 Gecko 和 Trident,缺點是 對于網頁代碼的容錯性不高,也就是說對網頁代碼的兼容性較低,會 使一些編寫不標準的網頁無法正確顯示。WebKit 前身是 KDE 小組的 KHTML 引擎,可以說 WebKit 是 KHTML 的一個開源的分支。
Blink:谷歌在 Chromium Blog 上發表博客,稱將與蘋果的開源瀏覽 器核心 Webkit 分道揚鑣,在 Chromium 項目中研發 Blink 渲染引 擎(即瀏覽器核心),內置于 Chrome 瀏覽器之中。其實 Blink 引 擎就是 Webkit 的一個分支,就像 webkit 是 KHTML 的分支一樣。 Blink 引擎現在是谷歌公司與 Opera Software 共同研發,上面提到過的,Opera 棄用了自己的 Presto 內核,加入 Google 陣營,跟隨 谷歌一起研發 Blink。
14. 瀏覽器的渲染過程
首先解析收到的文檔,根據文檔定義構建一棵 DOM 樹,DOM 樹是由 DOM 元素及屬性節點組成的。
然后對 CSS 進行解析,生成 CSSOM 規則樹。
根據 DOM 樹和 CSSOM 規則樹構建渲染樹。渲染樹的節點被稱為渲染 對象,渲染對象是一個包含有顏色和大小等屬性的矩形,渲染對象和 DOM 元素相對應,但這種對應關系不是一對一的,不可見的 DOM 元 素不會被插入渲染樹。還有一些 DOM 元素對應幾個可見對象,它們 一般是一些具有復雜結構的元素,無法用一個矩形來描述。
當渲染對象被創建并添加到樹中,它們并沒有位置和大小,所以當瀏 覽器生成渲染樹以后,就會根據渲染樹來進行布局(也可以叫做回流)。 這一階段瀏覽器要做的事情是要弄清楚各個節點在頁面中的確切位 置和大小。通常這一行為也被稱為“自動重排”。
布局階段結束后是繪制階段,遍歷渲染樹并調用渲染對象的 paint 方法將它們的內容顯示在屏幕上,繪制使用 UI 基礎組件。
大致過程如圖所示:
?注意:這個過程是逐步完成的,為了更好的用戶體驗,渲染引擎將會 盡可能早的將內容呈現到屏幕上,并不會等到所有的 html 都解析完 成之后再去構建和布局 render 樹。它是解析完一部分內容就顯示一 部分內容,同時,可能還在通過網絡下載其余內容。
15. 渲染過程中遇到 JS 文件如何處理?
JavaScript 的加載、解析與執行會阻塞文檔的解析,也就是說,在 構建 DOM 時,HTML 解析器若遇到了 JavaScript,那么它會暫停文 檔的解析,將控制權移交給 JavaScript 引擎,等 JavaScript 引擎 運行完畢,瀏覽器再從中斷的地方恢復繼續解析文檔。也就是說,如 果想要首屏渲染的越快,就越不應該在首屏就加載 JS 文件,這也是 都建議將 script 標簽放在 body 標簽底部的原因。當然在當下,并 不是說 script 標簽必須放在底部,因為你可以給 script 標簽添加 defer 或者 async 屬性。
16. 前端儲存的方式有哪些?
cookies: 在 HTML5 標準前本地儲存的主要方式,優點是兼容性好,
請求頭自帶 cookie方便,缺點是大小只有 4k,自動請求頭加入cookie
浪費流量,每個 domain 限制 20 個 cookie,使用起來麻煩,需要自 行封裝;
localStorage:HTML5 加入的以鍵值對(Key-Value)為標準的方式, 優點是操作方便,永久性儲存(除非手動刪除),大小為 5M,兼容 IE8+ ;
sessionStorage:與 localStorage 基本類似,區別是 sessionStorage 當?面關閉后會被清理,而且與 cookie、localStorage 不同,他不 能在所有同源窗口中共享,是會話級別的儲存方式;
Web SQL:2010 年被 W3C 廢棄的本地數據庫數據存儲方案,但是主流 瀏覽器(火狐除外)都已經有了相關的實現,web sql 類似于 SQLite, 是 真 正 意 義 上 的 關 系 型 數 據 庫 ,用 s q l 進 行 操 作 ,當 我 們 用 J a v a S c r i p t 時要進行轉換,較為繁瑣;
IndexedDB:是被正式納入HTML5 標準的數據庫儲存方案,它是 NoSQL 數據庫,用鍵值對進行儲存,可以進行快速讀取操作,非常適合 web 場景,同時用JavaScript 進行操作會非常便。
17. 事件是什么?事件模型?
事件是用戶操作網頁時發生的交互動作,比如 click/move, 事件除 了用戶觸發的動作外,還可以是文檔加載,窗口滾動和大小調整。事 件被封裝成一個 event 對象,包含了該事件發生時的所有相關信息 ( event 的屬性)以及可以對事件進行的操作( event 的方法)。
事件是用戶操作網頁時發生的交互動作或者網頁本身的一些操作,現 代瀏覽器一共有三種事件模型:
DOM0 級事件模型,這種模型不會傳播,所以沒有事件流的概念,但 是現在有的瀏覽器支持以冒泡的方式實現,它可以在網頁中直接定義
監聽函數,也可以通過 js 屬性來指定監聽函數。所有瀏覽器都兼容 這種方式。直接在 dom 對象上注冊事件名稱,就是 DOM0 寫法。
IE 事件模型,在該事件模型中,一次事件共有兩個過程,事件處理 階段和事件冒泡階段。事件處理階段會首先執行目標元素綁定的監聽 事件。然后是事件冒泡階段,冒泡指的是事件從目標元素冒泡到 document,依次檢查經過的節點是否綁定了事件監聽函數,如果有則 執行。這種模型通過 attachEvent 來添加監聽函數,可以添加多個 監聽函數,會按順序依次執行。
DOM2 級事件模型,在該事件模型中,一次事件共有三個過程,第一 個過程是事件捕獲階段。捕獲指的是事件從 document 一直向下傳播 到目標元素,依次檢查經過的節點是否綁定了事件監聽函數,如果有 則執行。后面兩個階段和 IE 事件模型的兩個階段相同。這種事件模 型,事件綁定的函數是 addEventListener,其中第三個參數可以指 定事件是否在捕獲階段執行。
18. 對事件循環的理解
因為 js 是單線程運行的,在代碼執行時,通過將不同函數的執行上 下文壓入執行棧中來保證代碼的有序執行。在執行同步代碼時,如果 遇到異步事件,js 引擎并不會一直等待其返回結果,而是會將這個 事件掛起,繼續執行執行棧中的其他任務。當異步事件執行完畢后, 再將異步事件對應的回調加入到一個任務隊列中等待執行。任務隊列 可以分為宏任務隊列和微任務隊列,當當前執行棧中的事件執行完畢 后,js 引擎首先會判斷微任務隊列中是否有任務可以執行,如果有 就將微任務隊首的事件壓入棧中執行。當微任務隊列中的任務都執行 完成后再去執行宏任務隊列中的任務。
?
Event Loop 執行順序如下所示: 首先執行同步代碼,這屬于宏任務
當執行完所有同步代碼后,執行棧為空,查詢是否有異步代碼需要執 行
執行所有微任務 當執行完所有微任務后,如有必要會渲染頁面 然后開始下一輪 Event Loop,執行宏任務中的異步代碼
總結
以上是生活随笔為你收集整理的2022前端面试题上岸手册-浏览器部分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 支付系列-对接支付宝支付
- 下一篇: 程序员与乞丐的故事