更新:謝謝你們的支持,最近折騰了一個博客官網出來,方便你們系統閱讀,後續會有更多內容和更多優化,猛戳這裏查看javascript
------ 如下是正文 ------css
半月刊第二期來啦,這段時間 Daily-Interview-Question 新增了 10 道高頻面試題,今天就把最近半月彙總的面試題和部分答案發給你們,幫助你們查漏補缺。前端
歡迎 PR 你認爲不錯的面試題,歡迎在項目 Issue 區留下你的答案,若有問題歡迎討論。java
項目地址是:Daily-Interview-Questionnode
在 HTTP/1 中,每次請求都會創建一次TCP鏈接,也就是咱們常說的3次握手4次揮手,這在一次請求過程當中佔用了至關長的時間,即便開啓了 Keep-Alive ,解決了屢次鏈接的問題,可是依然有兩個效率上的問題:react
HTTP2採用二進制格式傳輸,取代了HTTP1.x的文本格式,二進制格式解析更高效。 多路複用代替了HTTP1.x的序列和阻塞機制,全部的相同域名請求都經過同一個TCP鏈接併發完成。在HTTP1.x中,併發多個請求須要多個TCP鏈接,瀏覽器爲了控制資源會有6-8個TCP鏈接都限制。 HTTP2中css3
更多解析:github.com/Advanced-Fr…git
更多解析:github.com/Advanced-Fr…github
若是A 與 B 創建了正常鏈接後,從未相互發過數據,這個時候 B 忽然機器重啓,問 A 此時處於 TCP 什麼狀態?如何消除服務器程序中的這個狀態?(超綱題,瞭解便可)面試
由於B會在重啓以後進入tcp狀態機的listen狀態,只要當a從新發送一個數據包(不管是syn包或者是應用數據),b端應該會主動發送一個帶rst位的重置包來進行鏈接重置,因此a應該在syn_sent狀態。
在 React 中,若是是由 React 引起的事件處理(好比經過 onClick 引起的事件處理),調用 setState 不會同步更新 this.state,除此以外的 setState 調用會同步執行 this.state。所謂「除此以外」,指的是繞過 React 經過 addEventListener 直接添加的事件處理函數,還有經過 setTimeout/setInterval 產生的異步調用。
**緣由:**在 React 的 setState 函數實現中,會根據一個變量 isBatchingUpdates 判斷是直接更新 this.state 仍是放到隊列中回頭再說,而 isBatchingUpdates 默認是 false,也就表示 setState 會同步更新 this.state,可是,有一個函數 batchedUpdates,這個函數會把 isBatchingUpdates 修改成t rue,而當 React 在調用事件處理函數以前就會調用這個 batchedUpdates,形成的後果就是由 React 控制的事件處理過程 setState 不會同步更新 this.state。
class Example extends React.Component {
constructor() {
super();
this.state = {
val: 0
};
}
componentDidMount() {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 1 次 log
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 2 次 log
setTimeout(() => {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 3 次 log
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 4 次 log
}, 0);
}
render() {
return null;
}
};
複製代碼
解析:
一、第一次和第二次都是在 react 自身生命週期內,觸發時 isBatchingUpdates 爲 true,因此並不會直接執行更新 state,而是加入了 dirtyComponents,因此打印時獲取的都是更新前的狀態 0。
二、兩次 setState 時,獲取到 this.state.val 都是 0,因此執行時都是將 0 設置成 1,在 react 內部會被合併掉,只執行一次。設置完成後 state.val 值爲 1。
三、setTimeout 中的代碼,觸發時 isBatchingUpdates 爲 false,因此可以直接進行更新,因此連着輸出 2,3。
輸出: 0 0 2 3
解析:
npm install
命令.npm
目錄裏node_modules
目錄輸入 npm install 命令並敲下回車後,會經歷以下幾個階段(以 npm 5.5.1 爲例):
當前 npm 工程若是定義了 preinstall 鉤子此時會被執行。
首先須要作的是肯定工程中的首層依賴,也就是 dependencies 和 devDependencies 屬性中直接指定的模塊(假設此時沒有添加 npm install 參數)。
工程自己是整棵依賴樹的根節點,每一個首層依賴模塊都是根節點下面的一棵子樹,npm 會開啓多進程從每一個首層依賴模塊開始逐步尋找更深層級的節點。
獲取模塊是一個遞歸的過程,分爲如下幾步:
上一步獲取到的是一棵完整的依賴樹,其中可能包含大量重複模塊。好比 A 模塊依賴於 lodash,B 模塊一樣依賴於 lodash。在 npm3 之前會嚴格按照依賴樹的結構進行安裝,所以會形成模塊冗餘。
從 npm3 開始默認加入了一個 dedupe 的過程。它會遍歷全部節點,逐個將模塊放在根節點下面,也就是 node-modules 的第一層。當發現有重複模塊時,則將其丟棄。
這裏須要對重複模塊進行一個定義,它指的是模塊名相同且 semver 兼容。每一個 semver 都對應一段版本容許範圍,若是兩個模塊的版本容許範圍存在交集,那麼就能夠獲得一個兼容版本,而沒必要版本號徹底一致,這可使更多冗餘模塊在 dedupe 過程當中被去掉。
這一步將會更新工程中的 node_modules,並執行模塊中的生命週期函數(按照 preinstall、install、postinstall 的順序)。
當前 npm 工程若是定義了鉤子此時會被執行(按照 install、postinstall、prepublish、prepare 的順序)。
最後一步是生成或更新版本描述文件,npm install 過程完成。
Object.prototype.toString.call() 、 instanceof 以及 Array.isArray()
解析:
每個繼承 Object 的對象都有 toString
方法,若是 toString
方法沒有重寫的話,會返回 [Object type]
,其中 type 爲對象的類型。但當除了 Object 類型的對象外,其餘類型直接使用 toString
方法時,會直接返回都是內容的字符串,因此咱們須要使用call或者apply方法來改變toString方法的執行上下文。
const an = ['Hello','An'];
an.toString(); // "Hello,An"
Object.prototype.toString.call(an); // "[object Array]"
複製代碼
這種方法對於全部基本的數據類型都能進行判斷,即便是 null 和 undefined 。
Object.prototype.toString.call('An') // "[object String]"
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(function(){}) // "[object Function]"
Object.prototype.toString.call({name: 'An'}) // "[object Object]"
複製代碼
Object.prototype.toString.call()
經常使用於判斷瀏覽器內置對象。
instanceof
的內部機制是經過判斷對象的原型鏈中是否是能找到類型的 prototype
。
使用 instanceof
判斷一個對象是否爲數組,instanceof
會判斷這個對象的原型鏈上是否會找到對應的 Array
的原型,找到返回 true
,不然返回 false
。
[] instanceof Array; // true
複製代碼
但 instanceof
只能用來判斷對象類型,原始類型不能夠。而且全部對象類型 instanceof Object 都是 true。
[] instanceof Object; // true
複製代碼
功能:用來判斷對象是否爲數組
instanceof 與 isArray
當檢測Array實例時,Array.isArray
優於 instanceof
,由於 Array.isArray
能夠檢測出 iframes
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]
// Correctly checking for Array
Array.isArray(arr); // true
Object.prototype.toString.call(arr); // true
// Considered harmful, because doesn't work though iframes
arr instanceof Array; // false
複製代碼
Array.isArray()
與 Object.prototype.toString.call()
Array.isArray()
是ES5新增的方法,當不存在 Array.isArray()
,能夠用 Object.prototype.toString.call()
實現。
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
複製代碼
解析:
Flow Based Layout
)HTML
解析成DOM
,把CSS
解析成CSSOM
,DOM
和CSSOM
合併就產生了渲染樹(Render Tree
)。RenderTree
,咱們就知道了全部節點的樣式,而後計算他們在頁面上的大小和位置,最後把節點繪製到頁面上。Render Tree
的計算一般只須要遍歷一次就能夠完成,但table及其內部元素除外,他們可能須要屢次計算,一般要花3倍於同等元素的時間,這也是爲何要避免使用table佈局的緣由之一。因爲節點的幾何屬性發生改變或者因爲樣式發生改變而不會影響佈局的,稱爲重繪,例如outline
, visibility
, color
、background-color
等,重繪的代價是高昂的,由於瀏覽器必須驗證DOM樹上其餘節點元素的可見性。
迴流是佈局或者幾何屬性須要改變就稱爲迴流。迴流是影響瀏覽器性能的關鍵因素,由於其變化涉及到部分頁面(或是整個頁面)的佈局更新。一個元素的迴流可能會致使了其全部子元素以及DOM中緊隨其後的節點、祖先節點元素的隨後的迴流。
<body>
<div class="error">
<h4>個人組件</h4>
<p><strong>錯誤:</strong>錯誤的描述…</p>
<h5>錯誤糾正</h5>
<ol>
<li>第一步</li>
<li>第二步</li>
</ol>
</div>
</body>
複製代碼
在上面的HTML片斷中,對該段落(<p>
標籤)迴流將會引起強烈的迴流,由於它是一個子節點。這也致使了祖先的迴流(div.error
和body
– 視瀏覽器而定)。此外,<h5>
和<ol>
也會有簡單的迴流,由於這些節點在DOM中迴流元素以後。大部分的迴流將致使頁面的從新渲染。
迴流一定會發生重繪,重繪不必定會引起迴流。
現代瀏覽器大多都是經過隊列機制來批量更新佈局,瀏覽器會把修改操做放在隊列中,至少一個瀏覽器刷新(即16.6ms)纔會清空隊列,但當你獲取佈局信息的時候,隊列中可能有會影響這些屬性或方法返回值的操做,即便沒有,瀏覽器也會強制清空隊列,觸發迴流與重繪來確保返回正確的值。
主要包括如下屬性或方法:
offsetTop
、offsetLeft
、offsetWidth
、offsetHeight
scrollTop
、scrollLeft
、scrollWidth
、scrollHeight
clientTop
、clientLeft
、clientWidth
、clientHeight
width
、height
getComputedStyle()
getBoundingClientRect()
因此,咱們應該避免頻繁的使用上述的屬性,他們都會強制渲染刷新隊列。
table
的從新佈局。<div>
<a> <span></span> </a>
</div>
<style>
span {
color: red;
}
div > a > span {
color: red;
}
</style>
複製代碼
對於第一種設置樣式的方式來講,瀏覽器只須要找到頁面中全部的 span
標籤而後設置顏色,可是對於第二種設置樣式的方式來講,瀏覽器首先須要找到全部的 span
標籤,而後找到 span
標籤上的 a
標籤,最後再去找到 div
標籤,而後給符合這種條件的 span
標籤設置顏色,這樣的遞歸過程就很複雜。因此咱們應該儘量的避免寫過於具體的 CSS 選擇器,而後對於 HTML 來講也儘可能少的添加無心義標籤,保證層級扁平。
requestAnimationFrame
,詳見探討 requestAnimationFrame。will-change
、video
、iframe
等標籤,瀏覽器會自動將該節點變爲圖層。transform
、opacity
、filters
這些動畫不會引發迴流重繪 。可是對於動畫的其它屬性,好比background-color
這些,仍是會引發迴流重繪的,不過它仍是能夠提高這些動畫的性能。JavaScript
避免頻繁操做樣式,最好一次性重寫style
屬性,或者將樣式列表定義爲class
並一次性更改class
屬性。
避免頻繁操做DOM,建立一個documentFragment
,在它上面應用全部DOM操做
,最後再把它添加到文檔中。
避免頻繁讀取會引起迴流/重繪的屬性,若是確實須要屢次使用,就用一個變量緩存起來。
對具備複雜動畫的元素使用絕對定位,使它脫離文檔流,不然會引發父元素及後續元素頻繁迴流。
解析:
發佈-訂閱模式是觀察者模式的一種變體。發佈-訂閱只是把一部分功能抽象成一個獨立的ChangeManager。
都是某個對象(subject, publisher)改變,使依賴於它的多個對象(observers, subscribers)獲得通知。
總的來講,發佈-訂閱模式適合更復雜的場景。
在「一對多」的場景下,發佈者的某次更新只想通知它的部分訂閱者?
在「多對一」或者「多對多」場景下。一個訂閱者依賴於多個發佈者,某個發佈者更新後是否須要通知訂閱者?仍是等全部發布者都更新完畢再通知訂閱者?
這些邏輯均可以放到ChangeManager裏。
歡迎在 Issue 區留下你的答案。
進階系列文章彙總以下,內有優質前端資料,以爲不錯點個star。
我是木易楊,網易高級前端工程師,跟着我每週重點攻克一個前端面試重難點。接下來讓我帶你走進高級前端的世界,在進階的路上,共勉!