JavaScript經典面試題的專業回答(一)
面試官問:如何快速排查記憶體洩露?
相信我,面試的基調從一開始就定好了。面試官是往死裡問還是往平裡問,這都取決於看起來簡單卻需要猛料的回答。
1.地道解釋一下記憶體洩露
記憶體洩露的解釋:程式中己動態分配的堆記憶體由於某種原因未釋放或無法釋放。
面試官:那究竟是什麼原因導致沒有釋放呢?
根據JS的垃圾回收機制,當記憶體中引用的次數為0的時候記憶體才會被回收
全域性執行上下文中的物件被標記為不再使用才會被釋放
2.記憶體洩露的幾種場景
- 全域性變數過多。
通常是變數未被定義或者胡亂引用了全域性變數
// main.js // 場景1 function a(){ b=10; } a(); b++; // 場景2 setTimeout(()=>{ console.log(b) },1000)
- 閉包。 未手動解決必包遺留的記憶體引用。
定義了閉包就要消除閉包帶來的副作用。
function closuer (){
const b = 0;
return (c)=> b + c
}
const render = closuer();
render();
render = null; // 手動設定為null,GC會自己去清除
- 事件監聽未被移除
function addEvent (){ const node = document.getElementById('warp'); node.addEventListener('touchmove',()=>{ console.log('In Move'); }) } const onTouchEnd = (){ const node = document.getElementById('warp'); node. } useEffect(()=>()=>{ const node = document.getElementById('warp'); node.removeEventListener('touchmove'); }) // 類似react 生命週期函式: componentWillUnmount render(<div id='warp' onTouchEnd={onTouchEnd}> // code... </div>)
- 快取。 不管是啥快取,都需要設定好過期時間。
面試官: 那你能不能說說你是如何排查記憶體洩露的?
分析一波:到這,回答中規中矩。但面試官的問題真的就到這了嗎? 明顯不是。 面試官問你是如何排查問題,其實就是再問,你是如何定位到問題的。
也就是說,記憶體洩露會導致頁面卡頓,甚至是頁面崩潰。相信你在用APP得開發包或者開發包測試問題的時候,肯定遇到過整個APP閃退的事情,因為在真機器除錯的過程中難免會遇見記憶體不夠用的時候。
那麼,問題來了。 記憶體洩露會導致頁面卡頓或者崩潰,那頁面卡頓就是記憶體洩露導致的嗎? 所以面試官真正想問的是,你是如何發現某個頁面有可能發生了記憶體洩露,並且你是如何診斷該問題是記憶體洩漏引起的。
我在其它文章裡有提過,前端效能優化首先得確立一些效能指標,那記憶體洩漏不正式效能指標的一種嗎?那明確了指標不就是該去獲取相關資料,然後上報給效能平臺嗎?
3.記憶體洩漏相關效能指標的確立
- window 物件上新增加的屬性數量
- 在載入頁面之前
Object.kyes(window)
- 離開頁面(路由跳轉、頁面關閉、後臺APP關閉等)之前
Object.kyes(window)
- 在載入頁面之前
- 一些特殊函式,例如產生閉包的函式變數是否重新賦值為null. 也就是說你寫的閉包有被清理掉嗎?或者說,
function closuer(){
const a = 0;
return (b)=> a + b
}
API.addClosuer(closuer);
const result = closuer();
API.addClosuer(result);
result = null;
closuer = null;
// 記錄頁面離開的時間,和被監聽的閉包函式有沒有被釋放。
const list = API.getClosuer(); // 被監聽的閉包函式集合,最好的結果就是 {closuer:null,result: null,...}
API.上報(API.getClosuer());
這樣,你的效能平臺上就能看見這一次上報的資料,頁面裡什麼時候產生了閉包,又是什麼時候閉包被清除了,也就一清二楚。
-
事件觸發的次數以及事件處理的時間。
- 如果js主執行緒堵塞了,那當下場景的事件觸發也就一定會延遲或者無限等待。 這裡用
performance.now
performance.now()
方法返回當前網頁從performance.timing.navigationStart
到當前時間之間的微秒數,其精度可達100萬分之一秒
。performance.now()
近似等於Date.now()
,但前者返回的是毫秒,後者返回的是微秒,後者的精度比前者高1000倍。
- 如果js主執行緒堵塞了,那當下場景的事件觸發也就一定會延遲或者無限等待。 這裡用
-
頁面DOM元素數量是否異常。
-
深度優先遍歷,獲取DOM樹的深度。這裡可以根據不同場景不同頁面來設定DOM樹深度的最大閥值。超過最大閥值則平臺進行預警。 因為這意味著頁面有動態新增DOM的事情發生。
-
FPS,有明顯長波段的不平穩。
-
重繪的次數。
-
最後
為了讓大家快速精通JavaScript,在這裡免費分享給大家一份Javascript學習指南。
Javascript學習指南文件涵蓋了javascript 語言核心、詞法結構 、型別、值和變數 、表示式和運算子 、語句、物件 、陣列 、函式 、類和模組 、 正則表示式的模式匹配、 javascript的子集和擴充套件 、伺服器端javascript /客戶端javascript 、web瀏覽器中的javascript 、window物件 、指令碼化文件、指令碼化css 、事件處理等22章知識點。內容豐富又詳細,拿下網際網路一線公司offfer的小夥伴都在看。
每個知識點都有左側導航書籤頁,看的時候十分方便,由於內容較多,下面列舉的部分內容和圖片。
物件
- 建立物件
- 屬性的查詢和設定
- 刪除屬性
- 檢測屬性
- 列舉屬性
- 屬性getter和setter
- 屬性的特性
陣列
- 建立陣列
- 陣列元素的讀和寫
- 稀疏陣列
- 陣列長度
- 陣列元素的新增和刪除
- 陣列遍歷
- 多維陣列
函式
- 函式定義
- 函式呼叫
- 函式的實參和形參
- 作為值的函式
- 作為名稱空間的函式
- 閉包
- 函式屬性、方法和建構函式
類和模組
- 類和原型
- 類和建構函式
- javascript中java式的類繼承
- 類的擴充
- 類和型別
- javascript中的面向物件技術
- 子類
正則表示式的模式匹配
- 正則表示式的定義
- 用於模式匹配的string方法
- regexp物件
javascript的子集和擴充套件
- javascript的子集
- 常量和區域性變數
- 解構賦值
- 迭代
- 函式簡寫
- 多catch 從句
- e4x: ecmascript for xml
web瀏覽器中的javascript
- 客戶端javascript
- 在html裡嵌入javascript
- javascript程式的執行
- 相容性和互用性
- 可訪問性
- 安全性
- 客戶端框架
window物件
- 計時器
- 瀏覽器定位和導航
- 瀏覽歷史
- 瀏覽器和螢幕資訊
- 對話方塊
- 錯誤處理
- 作為window物件屬性的文件元素
如果你有其他語言的程式設計經歷,這份文件會有助你瞭解JavaScript是一門高階的、動態的、弱型別的程式語言,非常適合面向物件和函式式的程式設計風格。
我在這裡將這份完整版的JS學習指南電子版文件提供出來,感興趣的朋友都可以找我拿一份學習!(純免費的一個分享,希望能給大家帶來實質性的幫助)
快速入手通道:【點選這領取Javascript學習指南電子版】
你的支援,我的動力;祝各位前程似錦,offer不斷!!!