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

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

前端必備 | 10道瀏覽器面試題解析,你會做嗎?

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

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

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

  1. 「用戶界面」?– 包括地址欄、前進/后退按鈕、書簽菜單等。
  2. 「瀏覽器引擎」?– 在用戶界面和呈現(xiàn)引擎之間傳送指令。
  3. 「呈現(xiàn)引擎」?– 負責顯示請求的內(nèi)容。如果請求的內(nèi)容是 HTML,它就負責解析 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 瀏覽器的每個標簽頁都分別對應(yīng)一個呈現(xiàn)引擎實例。每個標簽頁都是一個獨立的進程。
3. 為什么JavaScript是單線程的,與異步?jīng)_突嗎

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

JS單線程是指一個瀏覽器進程中只有一個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();
}復制代碼

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

異步機制是瀏覽器的兩個或以上常駐線程共同完成的,舉個例子,比如異步請求由兩個常駐線程,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í)行時間是大于或等于指定時間的,不保證能準確定時的)。
所以這么說,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)不可預期的結(jié)果,瀏覽器設(shè)置?「GUI 渲染線程與 JavaScript 引擎為互斥」的關(guān)系。
有個需要注意的點就是:
「有時候JS需要等到CSS的下載,這是為什么呢?」
仔細思考一下,其實這樣做是有道理的,如果腳本的內(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)不可預期的結(jié)果,瀏覽器設(shè)置?「GUI 渲染線程與 JavaScript 引擎為互斥」的關(guān)系。
當 JavaScript 引擎執(zhí)行時 GUI 線程會被掛起,GUI 更新會被保存在一個隊列中等到引擎線程空閑時立即被執(zhí)行。
當瀏覽器在執(zhí)行 JavaScript 程序的時候,GUI 渲染線程會被保存在一個隊列中,直到 JS 程序執(zhí)行完成,才會接著執(zhí)行。
因此如果 JS 執(zhí)行的時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染加載阻塞的感覺。
另外,如果 JavaScript 文件中沒有操作 DOM 相關(guān)代碼,就可以將該 JavaScript 腳本設(shè)置為異步加載,通過 async 或 defer 來標記代碼。
6. defer 和 async 的區(qū)別 ?
  • 兩者都是異步去加載外部JS文件,不會阻塞DOM解析
  • Async是在外部JS加載完成后,瀏覽器空閑時,Load事件觸發(fā)前執(zhí)行,標記為async的腳本并不保證按照指定他們的先后順序執(zhí)行,該屬性對于內(nèi)聯(lián)腳本無作用 (即沒有「src」屬性的腳本)。
  • defer是在JS加載完成后,整個文檔解析完成后,觸發(fā)?DOMContentLoaded?事件前執(zhí)行,如果缺少?src?屬性(即內(nèi)嵌腳本),該屬性不應(yīng)被使用,因為這種情況下它不起作用
7. DOMContentLoaded 與 load 的區(qū)別 ?

  • DOMContentLoaded事件觸發(fā)時:僅當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 標簽中包含 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進行批量的 DOM 操作
  • 對于 resize、scroll 等進行防抖/節(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í)行的時機。要做到控制執(zhí)行的時機,我們可以通過「一個開關(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);
};
};復制代碼

函數(shù)防抖(debounce)

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

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

代碼:

?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)
}
}復制代碼
如何使用 debounce 和 throttle 以及常見的坑

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

適合應(yīng)用場景

防抖

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

節(jié)流

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

正好跟節(jié)流有點關(guā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

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

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

rAF與 setTimeout 相比

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

具體一點講就是,系統(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)象,也不會導致動畫出現(xiàn)卡頓的問題。

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

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

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

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

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

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

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

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

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

rAF與節(jié)流相比

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

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

優(yōu)點

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

缺點

  • 動畫的開始/取消需要開發(fā)者自己控制,不像 ‘.debounce’ 或 ‘.throttle’由函數(shù)內(nèi)部處理。
  • 瀏覽器標簽未激活時,一切都不會執(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)站、手機應(yīng)用、小程序、快應(yīng)用、桌面應(yīng)用、后臺開發(fā)等多領(lǐng)域開發(fā)課程,新增Egg、TypeScript、Vue、React、HybridAPP等時下最流行的新技術(shù),結(jié)合企業(yè)實際用人需求,只為培養(yǎng)更多高端IT技術(shù)人才。