国产色诱美女免费视频|欧美精彩狠狠色丁香婷婷|91黑人|日本黄色小视频|欧美一级黄色视频在这里免费观看

IT培訓(xùn)-高端面授IT培訓(xùn)機(jī)構(gòu)
云和教育:云和數(shù)據(jù)集團(tuán)高端IT職業(yè)教育品牌
  • 國家級
    全民數(shù)字素養(yǎng)與技能培訓(xùn)基地
  • 河南省
    第一批產(chǎn)教融合型企業(yè)建設(shè)培育單位
  • 鄭州市
    數(shù)字技能人才(碼農(nóng))培養(yǎng)評價聯(lián)盟

收藏 | 10道瀏覽器面試題解析

  • 發(fā)布時間:
    2020-12-16
  • 版權(quán)所有:
    云和教育
  • 分享:
前言
Preface

想要成為一名合格的前端工程師,掌握相關(guān)瀏覽器的工作原理是必備的,這樣子才會有一個完整知識體系,要是「能參透瀏覽器的工作原理,你就能解決80%的前端難題」。
今天總結(jié)了10道瀏覽器面試題及解析,作為前端開發(fā)工程師的你趕緊來看看吧!

1. 常見的瀏覽器內(nèi)核有哪些?
2. 瀏覽器的主要組成部分是什么?

  1. 「用戶界面」?– 包括地址欄、前進(jìn)/后退按鈕、書簽菜單等。
  2. 「瀏覽器引擎」?– 在用戶界面和呈現(xiàn)引擎之間傳送指令。
  3. 「呈現(xiàn)引擎」?– 負(fù)責(zé)顯示請求的內(nèi)容。如果請求的內(nèi)容是 HTML,它就負(fù)責(zé)解析 HTML 和 CSS 內(nèi)容,并將解析后的內(nèi)容顯示在屏幕上。
  4. 「網(wǎng)絡(luò)」?– 用于網(wǎng)絡(luò)調(diào)用,比如 HTTP 請求。
  5. 「用戶界面后端」?-用于繪制基本的窗口小部件,比如組合框和窗口。
  6. 「JavaScript 解釋器」– 用于解析和執(zhí)行 JavaScript 代碼。
  7. 「數(shù)據(jù)存儲」?– 這是持久層。瀏覽器需要在硬盤上保存各種數(shù)據(jù),例如 Cookie。新的 HTML 規(guī)范 (HTML5) 定義了“網(wǎng)絡(luò)數(shù)據(jù)庫”,這是一個完整(但是輕便)的瀏覽器內(nèi)數(shù)據(jù)庫。
值得注意的是,和大多數(shù)瀏覽器不同,Chrome 瀏覽器的每個標(biāo)簽頁都分別對應(yīng)一個呈現(xiàn)引擎實例。每個標(biāo)簽頁都是一個獨立的進(jìn)程。
3. 為什么JavaScript是單線程的,與異步?jīng)_突嗎

補充:JS中其實是沒有線程概念的,所謂的單線程也只是相對于多線程而言。JS的設(shè)計初衷就沒有考慮這些,針對JS這種不具備并行任務(wù)處理的特性,我們稱之為“單線程”。

JS單線程是指一個瀏覽器進(jìn)程中只有一個JS的執(zhí)行線程,同一時刻內(nèi)只會有一段代碼在執(zhí)行。

舉個通俗例子,假設(shè)JS支持多線程操作的話,JS可以操作DOM,那么一個線程在刪除DOM,另外一個線程就在獲取DOM數(shù)據(jù),這樣子明顯不合理,這算是證明之一。

來看段代碼??

function foo() { ? ?console.log("first");
setTimeout(( function(){ ? ? ? ?console.log( 'second' );
}),5);
}
for (var i = 0; i < 1000000; i++) {
foo();
}復(fù)制代碼

打印結(jié)果就是首先是很多個first,然后再是second。

異步機(jī)制是瀏覽器的兩個或以上常駐線程共同完成的,舉個例子,比如異步請求由兩個常駐線程,JS執(zhí)行線程和事件觸發(fā)線程共同完成的。

  • JS執(zhí)行線程發(fā)起異步請求(瀏覽器會開啟一個HTTP請求線程來執(zhí)行請求,這時JS的任務(wù)完成,繼續(xù)執(zhí)行線程隊列中剩下任務(wù))
  • 然后在未來的某一時刻事件觸發(fā)線程監(jiān)視到之前的發(fā)起的HTTP請求已完成,它就會把完成事件插入到JS執(zhí)行隊列的尾部等待JS處理
再比如定時器觸發(fā)(settimeout和setinterval) 是由「瀏覽器的定時器線程」執(zhí)行的定時計數(shù),然后在定時時間把定時處理函數(shù)的執(zhí)行請求插入到JS執(zhí)行隊列的尾端(所以用這兩個函數(shù)的時候,實際的執(zhí)行時間是大于或等于指定時間的,不保證能準(zhǔn)確定時的)。
所以這么說,JS單線程與異步更多是瀏覽器行為,之間不沖突。
4. CSS加載會造成阻塞嗎

先給出結(jié)論

  • CSS不會阻塞DOM解析,但會阻塞DOM渲染。
  • CSS會阻塞JS執(zhí)行,并不會阻塞JS文件下載
先講一講CSSOM作用
  • 第一個是提供給 JavaScript 操作樣式表的能力
  • 第二個是為布局樹的合成提供基礎(chǔ)的樣式信息
  • 這個 CSSOM 體現(xiàn)在 DOM 中就是document.styleSheets。
由之前講過的瀏覽器渲染流程我們可以看出:
DOM 和 CSSOM通常是并行構(gòu)建的,所以「CSS 加載不會阻塞 DOM 的解析」
然而由于Render Tree 是依賴DOM Tree和 CSSOM Tree的,所以它必須等到兩者都加載完畢后,完成相應(yīng)的構(gòu)建,才開始渲染,因此,「CSS加載會阻塞DOM渲染」
由于 JavaScript 是可操縱 DOM 和 css 樣式 的,如果在修改這些元素屬性同時渲染界面(即 JavaScript 線程和 UI 線程同時運行),那么渲染線程前后獲得的元素數(shù)據(jù)就可能不一致了。
因此為了防止渲染出現(xiàn)不可預(yù)期的結(jié)果,瀏覽器設(shè)置?「GUI 渲染線程與 JavaScript 引擎為互斥」的關(guān)系。
有個需要注意的點就是:
「有時候JS需要等到CSS的下載,這是為什么呢?」
仔細(xì)思考一下,其實這樣做是有道理的,如果腳本的內(nèi)容是獲取元素的樣式,寬高等CSS控制的屬性,瀏覽器是需要計算的,也就是依賴于CSS。瀏覽器也無法感知腳本內(nèi)容到底是什么,為避免樣式獲取,因而只好等前面所有的樣式下載完后,再執(zhí)行JS
JS文件下載和CSS文件下載是并行的,有時候CSS文件很大,所以JS需要等待。
因此,樣式表會在后面的 js 執(zhí)行前先加載執(zhí)行完畢,所以「css 會阻塞后面 js 的執(zhí)行」
5. 為什么JS會阻塞頁面加載

先給出結(jié)論??

  • 「JS阻塞DOM解析」,也就會阻塞頁面
這也是為什么說JS文件放在最下面的原因,那為什么會阻塞DOM解析呢
你可以這樣子理解:
由于 JavaScript 是可操縱 DOM 的,如果在修改這些元素屬性同時渲染界面(即 JavaScript 線程和 UI 線程同時運行),那么渲染線程前后獲得的元素數(shù)據(jù)就可能不一致了。
因此為了防止渲染出現(xiàn)不可預(yù)期的結(jié)果,瀏覽器設(shè)置?「GUI 渲染線程與 JavaScript 引擎為互斥」的關(guān)系。
當(dāng) JavaScript 引擎執(zhí)行時 GUI 線程會被掛起,GUI 更新會被保存在一個隊列中等到引擎線程空閑時立即被執(zhí)行。
當(dāng)瀏覽器在執(zhí)行 JavaScript 程序的時候,GUI 渲染線程會被保存在一個隊列中,直到 JS 程序執(zhí)行完成,才會接著執(zhí)行。
因此如果 JS 執(zhí)行的時間過長,這樣就會造成頁面的渲染不連貫,導(dǎo)致頁面渲染加載阻塞的感覺。
另外,如果 JavaScript 文件中沒有操作 DOM 相關(guān)代碼,就可以將該 JavaScript 腳本設(shè)置為異步加載,通過 async 或 defer 來標(biāo)記代碼。
6. defer 和 async 的區(qū)別 ?
  • 兩者都是異步去加載外部JS文件,不會阻塞DOM解析
  • Async是在外部JS加載完成后,瀏覽器空閑時,Load事件觸發(fā)前執(zhí)行,標(biāo)記為async的腳本并不保證按照指定他們的先后順序執(zhí)行,該屬性對于內(nèi)聯(lián)腳本無作用 (即沒有「src」屬性的腳本)。
  • defer是在JS加載完成后,整個文檔解析完成后,觸發(fā)?DOMContentLoaded?事件前執(zhí)行,如果缺少?src?屬性(即內(nèi)嵌腳本),該屬性不應(yīng)被使用,因為這種情況下它不起作用
7. DOMContentLoaded 與 load 的區(qū)別 ?

  • DOMContentLoaded事件觸發(fā)時:僅當(dāng)DOM解析完成后,不包括樣式表,圖片等資源。
  • onload 事件觸發(fā)時,頁面上所有的 DOM,樣式表,腳本,圖片等資源已經(jīng)加載完畢。
那么也就是先DOMContentLoaded -> load,那么在Jquery中,使用(document).load(callback)監(jiān)聽的就是load事件。
那我們可以聊一聊它們與async和defer區(qū)別
帶async的腳本一定會在load事件之前執(zhí)行,可能會在DOMContentLoaded之前或之后執(zhí)行。
  • 情況1:HTML 還沒有被解析完的時候,async腳本已經(jīng)加載完了,那么 HTML 停止解析,去執(zhí)行腳本,腳本執(zhí)行完畢后觸發(fā)DOMContentLoaded事件
  • 情況2:HTML 解析完了之后,async腳本才加載完,然后再執(zhí)行腳本,那么在HTML解析完畢、async腳本還沒加載完的時候就觸發(fā)DOMContentLoaded事件
如果 script 標(biāo)簽中包含 defer,那么這一塊腳本將不會影響 HTML 文檔的解析,而是等到HTML 解析完成后才會執(zhí)行。而 DOMContentLoaded 只有在 defer 腳本執(zhí)行結(jié)束后才會被觸發(fā)。
  • 情況1:HTML還沒解析完成時,defer腳本已經(jīng)加載完畢,那么defer腳本將等待HTML解析完成后再執(zhí)行。defer腳本執(zhí)行完畢后觸發(fā)DOMContentLoaded事件
  • 情況2:HTML解析完成時,defer腳本還沒加載完畢,那么defer腳本繼續(xù)加載,加載完成后直接執(zhí)行,執(zhí)行完畢后觸發(fā)DOMContentLoaded事件
8. 為什么CSS動畫比JavaScript高效

我覺得這個題目說法上可能就是行不通,不能這么說,如果了解的話,都知道will-change只是一個優(yōu)化的手段,使用JS改變transform也可以享受這個屬性帶來的變化,所以這個說法上有點不妥。

所以圍繞這個問題展開話,更應(yīng)該說建議推薦使用CSS動畫,至于為什么呢,涉及的知識點大概就是重排重繪,合成,這方面的點,我在瀏覽器渲染流程中也提及了。

盡可能的避免重排和重繪,具體是哪些操作呢,如果非要去操作JS實現(xiàn)動畫的話,有哪些優(yōu)化的手段呢?

比如??

  • 使用createDocumentFragment進(jìn)行批量的 DOM 操作
  • 對于 resize、scroll 等進(jìn)行防抖/節(jié)流處理。
  • rAF優(yōu)化等等
剩下的東西就留給你們思考吧,希望我這是拋磚引玉吧(●’?’●)
9. 能不能實現(xiàn)事件防抖和節(jié)流

函數(shù)節(jié)流(throttle)

節(jié)流的意思是讓函數(shù)有節(jié)制地執(zhí)行,而不是毫無節(jié)制的觸發(fā)一次就執(zhí)行一次。什么叫有節(jié)制呢?就是在一段時間內(nèi),只執(zhí)行一次。

規(guī)定在一個單位時間內(nèi),只能觸發(fā)一次函數(shù)。如果這個單位時間內(nèi)觸發(fā)多次函數(shù),只有一次生效。

抓取一個關(guān)鍵的點:就是執(zhí)行的時機(jī)。要做到控制執(zhí)行的時機(jī),我們可以通過「一個開關(guān)」,與定時器setTimeout結(jié)合完成。

?function throttle(fn, delay) { ? ? ? ? ? ?let flag = true,
timer = null; ? ? ? ? ? ?return function (...args) { ? ? ? ? ? ? ? ?let context = this; ? ? ? ? ? ? ? ?if (!flag) return;
flag = false;
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(context, args);
flag = true;
}, delay);
};
};復(fù)制代碼

函數(shù)防抖(debounce)

在事件被觸發(fā)n秒后再執(zhí)行回調(diào),如果在這n秒內(nèi)又被觸發(fā),則重新計時。

核心思想:每次事件觸發(fā)都會刪除原有定時器,建立新的定時器。通俗意思就是反復(fù)觸發(fā)函數(shù),只認(rèn)最后一次,從最后一次開始計時。

代碼:

?function debounce(fn, delay) { ? ? ? ? ? ?let timer = null
return function (...args) { ? ? ? ? ? ? ? ?let context = this
if(timer) ? clearTimeout(timer)
timer = setTimeout(function() {
fn.apply(context, args)
},delay)
}
}復(fù)制代碼
如何使用 debounce 和 throttle 以及常見的坑

自己造一個 debounce / throttle 的輪子看起來多么誘人,或者隨便找個博文復(fù)制過來。「我是建議直接使用 underscore 或 Lodash」?。如果僅需要?_.debounce?和?_.throttle?方法,可以使用 Lodash 的自定義構(gòu)建工具,生成一個 2KB 的壓縮庫。使用以下的簡單命令即可:
npm i -g lodash-cli
npm i -g lodash-clilodash-cli include=debounce,throttle復(fù)制代碼
常見的坑是,不止一次地調(diào)用?_.debounce?方法:
// 錯誤$(window).on('scroll', function() {
_.debounce(doSomething, 300);
});// 正確$(window).on('scroll', _.debounce(doSomething, 200));復(fù)制代碼
debounce 方法保存到一個變量以后,就可以用它的私有方法?debounced_version.cancel(),lodash 和 underscore.js 都有效。
let debounced_version = _.debounce(doSomething, 200);$(window).on(‘scroll’, debounced_version);// 如果需要的話debounced_version.cancel();復(fù)制代碼

適合應(yīng)用場景

防抖

  • search搜索,用戶不斷輸入值時,用防抖來節(jié)約Ajax請求,也就是輸入框事件。
  • window觸發(fā)resize時,不斷的調(diào)整瀏覽器窗口大小會不斷的觸發(fā)這個事件,用防抖來讓其只觸發(fā)一次

節(jié)流

  • 鼠標(biāo)的點擊事件,比如mousedown只觸發(fā)一次
  • 監(jiān)聽滾動事件,比如是否滑到底部自動加載更多,用throttle判斷
  • 比如游戲中發(fā)射子彈的頻率(1秒發(fā)射一顆)
10. 談一談你對requestAnimationFrame(rAF)理解

正好跟節(jié)流有點關(guān)系,有點相似處,就準(zhǔn)備梳理一下這個知識點。

「高性能動畫是什么,那它衡量的標(biāo)準(zhǔn)是什么呢?」

動畫幀率可以作為衡量標(biāo)準(zhǔn),一般來說畫面在 60fps 的幀率下效果比較好。

換算一下就是,每一幀要在 16.7ms (16.7 = 1000/60) 內(nèi)完成渲染。

我們來看看MDN對它的解釋吧??

window.requestAnimationFrame() 方法告訴瀏覽器您希望執(zhí)行動畫并請求瀏覽器在下一次重繪之前調(diào)用指定的函數(shù)來更新動畫。該方法使用一個回調(diào)函數(shù)作為參數(shù),這個回調(diào)函數(shù)會在瀏覽器重繪之前調(diào)用。— MDN

當(dāng)我們調(diào)用這個函數(shù)的時候,我們告訴它需要做兩件事:

  1. 我們需要新的一幀;
  2. 當(dāng)你渲染新的一幀時需要執(zhí)行我傳給你的回調(diào)函數(shù)

rAF與 setTimeout 相比

rAF(requestAnimationFrame) 最大的優(yōu)勢是「由系統(tǒng)來決定回調(diào)函數(shù)的執(zhí)行時機(jī)」

具體一點講就是,系統(tǒng)每次繪制之前會主動調(diào)用 rAF 中的回調(diào)函數(shù),如果系統(tǒng)繪制率是 60Hz,那么回調(diào)函數(shù)就每16.7ms 被執(zhí)行一次,如果繪制頻率是75Hz,那么這個間隔時間就變成了 1000/75=13.3ms。

換句話說就是,rAF 的執(zhí)行步伐跟著系統(tǒng)的繪制頻率走。它能保證回調(diào)函數(shù)在屏幕每一次的繪制間隔中只被執(zhí)行一次(上一個知識點剛剛梳理完「函數(shù)節(jié)流」),這樣就不會引起丟幀現(xiàn)象,也不會導(dǎo)致動畫出現(xiàn)卡頓的問題。

另外它可以自動調(diào)節(jié)頻率。如果callback工作太多無法在一幀內(nèi)完成會自動降低為30fps。雖然降低了,但總比掉幀好。

與setTimeout動畫對比的話,有以下幾點優(yōu)勢

  • 當(dāng)頁面隱藏或者最小化時,setTimeout仍然在后臺執(zhí)行動畫,此時頁面不可見或者是不可用狀態(tài),動畫刷新沒有意義,而且浪費CPU。
  • rAF不一樣,當(dāng)頁面處理未激活的狀態(tài)時,該頁面的屏幕繪制任務(wù)也會被系統(tǒng)暫停,因此跟著系統(tǒng)步伐走的rAF也會停止渲染,當(dāng)頁面被激活時,動畫就從上次停留的地方繼續(xù)執(zhí)行,有效節(jié)省了 CPU 開銷。

什么時候調(diào)用呢

規(guī)范中似乎是這么去定義的:

  • 在重新渲染前調(diào)用。
  • 很可能在宏任務(wù)之后不去調(diào)用

這樣子分析的話,似乎很合理嘛,為什么要在重新渲染前去調(diào)用呢?因為rAF作為官方推薦的一種做流暢動畫所應(yīng)該使用的API,做動畫不可避免的去操作DOM,而如果是在渲染后去修改DOM的話,那就只能等到下一輪渲染機(jī)會的時候才能去繪制出來了,這樣子似乎不合理。

rAF在瀏覽器決定渲染之前給你最后一個機(jī)會去改變 DOM 屬性,然后很快在接下來的繪制中幫你呈現(xiàn)出來,所以這是做流暢動畫的不二選擇。

至于宏任務(wù),微任務(wù),這可以說起來就要展開篇幅了,暫時不在這里梳理了。

rAF與節(jié)流相比

跟?_.throttle(dosomething, 16)?等價。它是高保真的,如果追求更好的精確度的話,可以用瀏覽器原生的 API 。

可以使用 rAF API 替換 throttle 方法,考慮一下優(yōu)缺點:

優(yōu)點

  • 動畫保持 60fps(每一幀 16 ms),瀏覽器內(nèi)部決定渲染的最佳時機(jī)
  • 簡潔標(biāo)準(zhǔn)的 API,后期維護(hù)成本低

缺點

  • 動畫的開始/取消需要開發(fā)者自己控制,不像 ‘.debounce’ 或 ‘.throttle’由函數(shù)內(nèi)部處理。
  • 瀏覽器標(biāo)簽未激活時,一切都不會執(zhí)行。
  • 盡管所有的現(xiàn)代瀏覽器都支持 rAF ,IE9,Opera Mini 和 老的 Android 還是需要打補丁。
  • Node.js 不支持,無法在服務(wù)器端用于文件系統(tǒng)事件。

根據(jù)經(jīng)驗,如果 JavaScript 方法需要繪制或者直接改變屬性,我會選擇?requestAnimationFrame,只要涉及到重新計算元素位置,就可以使用它。

涉及到 AJAX 請求,添加/移除 class (可以觸發(fā) CSS 動畫),我會選擇?_.debounce?或者?_.throttle?,可以設(shè)置更低的執(zhí)行頻率(例子中的200ms 換成16ms)。

云和數(shù)據(jù)HTML5全棧精英班,經(jīng)過多年的技術(shù)迭代和項目革新,逐步發(fā)展成為集網(wǎng)站、手機(jī)應(yīng)用、小程序、快應(yīng)用、桌面應(yīng)用、后臺開發(fā)等多領(lǐng)域開發(fā)課程,新增Egg、TypeScript、Vue、React、HybridAPP等時下最流行的新技術(shù),結(jié)合企業(yè)實際用人需求,只為培養(yǎng)更多高端IT技術(shù)人才。