內容包括面試考點,答題技巧,以及一點工做後的經歷... 讀者能夠根據右側導航目錄,按需閱讀,但願各位都有所獲。前端
開篇不想暴擊,但頗有必要。每每咱們爲了面試,準備了好久,投了心儀的廠子,結果等來的不是面試通知,而是一封冰冷的郵件... 您的簡歷,與崗位要求不符
vue
通常這種狀況能夠總結爲幾類,評論歡迎補充:java
重要分析一下第 4 點,能夠解讀出不少東西:node
「Talk is cheap. Show me the code」
,建議:簡歷裏帶上你的 github、掘金等連接,若沒有?還不趕忙動起來!簡歷上面寫了什麼,決定了面試官會問你什麼。若是你寫的很泛,除非你真的很全面無敵,不然狀況會很糟。react
面試是有技巧的,簡單的一問一答太過死板,試着在回答的時候引伸向你擅長的領域,拋出一個個關鍵詞誘導考官提問。git
具體的例子,下文會涉及。但在此以前,咱們須要作足功課,務實基礎。此外,請務必準備一些殺手鐗,在須要的時候亮瞎考官的……,好比 HTTPS 全部加密算法
,chromium 進程 IPC 原理
,斐波拉契第 n 數的 logn 解法
,瀏覽器渲染過程
,Vue 編譯器架構
,快排以及手寫 V8 排序
。程序員
算法是大廠必考的項目,這裏筆者提供 leetcode 字節跳動的企業題庫,後面會慢慢補齊其餘廠的。github
進入正題,前端要往深了走,基礎很重要。面試
定義:有權訪問另外一個函數做用域中的變量的函數。ajax
產生緣由:先解釋下做用域鏈,而後說明當前環境存在指向父級做用域的引用。
應用:定時器 / 事件監聽 / ajax / Web Worker 等都有涉及,關鍵就是使用了回調函數……
面試時能夠展開的點,能夠引出下一個話題:閉包變量存在堆中一個名爲 [[scope]]
的對象內,同時閉包也常以 高階函數
的形式建立,V8 的 垃圾回收
機制也涉及到了閉包。
講到閉包,就會涉及到內存存儲空間的知識,進而能夠引伸到垃圾回收機制 GC。
咱們知道:棧中保存變量,函數調用完,棧頂空間自動銷燬,而後切換執行上下文,假如存儲對象很大,切換的開銷天然也變得巨大。因而,堆就出場了。
強調:V8 的 GC 做用的是堆而不是棧。
複製代碼
非增量
垃圾回收時需耗時 1 秒之久,這期間會致使 js 暫停、應用卡頓,形成性能降低,顯然,1.4G 是通過深思熟慮的。變量晉升
,兩個算法 mark-sweep 標記清除
,mark-compact 標記整理
。還有 增量標記算法
,這個算法優化將 GC 期間形成的 js 阻塞減小到本來的 1/6。微任務
階段進行。GC 還能夠展開的點:增量清理、增量整理、多核並行清理,內存泄漏,WeakMap、WeakSet 弱引用。
回答時,能夠按照如下順序來回答。
let obj = new Fn()
__proto__
屬性,全名 [double underscore proto] 讀做 dunder proto
便可。該屬性指向構造函數的原型對象。__proto__
指向父類對象,接着不斷追溯父類原型對象,直到指向 Object 對象爲止,再上面只剩 null 了。明白了原型鏈,那麼手寫 instanceof 就不在話下了。列出幾個經常使用的方法:
Object.getPrototypeOf(obj) // 獲取原型對象,好比 instanceof 源代碼
Object.setPrototypeOf(subClass, superClass) // 繼承父類的靜態方法
Object.prototype.hasOwnProperty(attr) // 檢查對象自身是否有該屬性
in // 檢查對象或原型對象中是否有該屬性 if (k in O) {}
Object.create(proto, [propertiesObject]) // 一個不帶任何原型鏈屬性、純淨且高度可定製的對象,好比數據字典能夠用 create(null) 代替 {} 初始化
這塊算是面試的重頭戲了,資料太多,照搬沒有意思,認清注意下面幾個點。
process.nextTick
。requestAnimationFrame
,接着是 UI 渲染,Web Worker,注意這幾個的順序。process.nextTick
:是獨立於 Event Loop 的任務隊列,且在微任務以前執行。花點時間詳細瞭解 Event Loop
裏面的細節是頗有必要的,畢竟主流前端框架中的批量更新,fiber 的調度,事務等都或多或少與之相關,在提升性能這一塊 Event Loop
能夠作的事情不少。
array[Symbol.iterator]().next()
的語法糖,forEach + await 別用就對了。設計模式並非多麼晦澀難懂的概念,咱們平常開發中多少都會接觸到。它是前人在實際生產項目中不斷迭代、試錯、修正、抽象而來的經驗總結,使用設計模式可讓你的代碼變得更加可維護、易於擴展。說人話就是日常能用就用,重構時必用。
工廠模式:組件化中經常使用的重構利器。
單例模式:分懶漢式和餓漢式,好比數據庫鏈接,vuex、redux 等狀態管理工具,甚至更復雜的場景,必須掌握。
觀察者模式:太多地方用了,好比 Vue 響應式中的收集依賴和觸發更新。
發佈-訂閱模式 與 觀察者模式 的區別:在觀察者模式中,觀察者是知道 目標 Subject 的,Subject 一直保持對觀察者進行記錄。然而,在發佈訂閱模式中,發佈者和訂閱者不知道對方的存在。它們只有經過一箇中間層,消息代理進行通訊,同時是異步的。在發佈訂閱模式中,組件是鬆散耦合的,正好和觀察者模式相反。
觀察者模式 舉例:你對某知名企業很感興趣(你做爲觀察者知道企業大名),投遞簡歷後企業維護你和其餘面試者的簡歷(企業知道了你),當職位空缺時主動通知你和其餘面試者。這個例子,雙方是直接的關係。
其實還有:狀態模式、策略模式 都比較常見,也比較簡單,一看就會,實際開發中若是寫煩了 if-else
,也能夠換換寫法,優雅一下。
享元模式、中介者模式,emmm...跟 發佈-訂閱模式 極其的相似。
而 適配器模式(用於封裝)、裝飾者模式(用於加強功能)、代理模式(Vue3 的 Proxy)較易混淆,有興趣就多瞭解。
主要講講主流框架
Vue
和React
,包括但不限於:框架演進、框架橫向對比、虛擬 Dom、渲染、響應原理、版本差別、Diff 算法等...
解釋器
經過詞法分析和語法分析將源碼轉成 AST,根據 AST 生成執行上下文。解釋器
根據 AST 生成 V8 字節碼。爲何不是二進制機器碼:機器碼太大,執行佔用太多內存。解釋器
逐行執行字節碼,遇到熱點代碼啓動 編譯器
進行編譯,生成對應的機器碼, 以優化執行效率。針對 Js 運行的性能優化:
科普:不少人在剛入門的時候對 V八、Webkit、JSCore、runtime 這幾個詞沒有概念,或者傻傻分不清,筆者在這裏簡單梳理下。
複製代碼
AST,彷佛處處都有它的影子,包括瀏覽器、主流框架、Webpack 等打包工具、Babel、跨平臺應用框架,如 uni-app 、Vue 轉小程序。瞭解了 AST,以後不管是優化仍是轉換,不過是增刪改查罷了。
解析模版,生成 AST 語法樹:
詞法分析:使用大量的正則表達式對模板進行解析,遇到標籤、文本的時候都會執行對應的鉤子進行相關處理。
優化:其中涉及 靜態節點優化
,設置 static 屬性用於 Diff 時剪枝,靜態節點就是一些不帶變量的文本節點,或者一些不帶 if 和 for 的節點。用於在下次渲染時直接跳過。
深度遍歷 AST,標記靜態節點以優化跳過比對,最後轉爲可執行的代碼。
總結:語法分析 -> 語法分析 -> 優化
到這裏,其實 AST 的任務已經結束。如下是 template 接下來的代碼邏輯。
AST 會通過 generate 函數獲得 render 函數,不一樣的節點有不一樣的 render 處理方式。render 生成虛擬 Dom,最後 patching,Diff,渲染 Dom。
3.引伸:flutter、React Native 的渲染機制
vue2.0 響應式原理 看這篇夠夠的了。
view 變化觸發 data 更新經過事件監聽
如下是 data 觸發 view 更新
v2 中是遞歸遍歷 data 中的全部的 property,並使用 Object.defineProperty
把這些 property 所有轉爲 getter/setter,在getter 中作數據依賴收集處理,在 setter 中 監聽數據的變化,並通知訂閱當前數據的地方
具體:
1.實現一個監聽器 Observer:對數據對象進行遍歷,包括子屬性對象的屬性,利用 Object.defineProperty()
對屬性都加上 setter 和 getter。這樣的話,給這個對象的某個值賦值,就會觸發 setter,那麼就能監聽到了數據變化。
2.實現一個解析器 Compile:解析 Vue 模板指令,將模板中的變量都替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變更,收到通知,調用更新函數進行數據更新。
3.實現一個訂閱者 Watcher:Watcher 訂閱者是 Observer 和 Compile 之間通訊的橋樑 ,主要的任務是訂閱 Observer 中的屬性值變化的消息,當收到屬性值變化的消息時,觸發解析器 Compile 中對應的更新函數。
4.實現一個訂閱器 Dep:訂閱器採用 發佈-訂閱 設計模式,用來收集訂閱者 Watcher,對監聽器 Observer 和 訂閱者 Watcher 進行統一管理。
限制:
沒法檢測對象屬性的添加與刪除,須要配合 set/delete
defineProperty 監聽 array 是有缺陷的:改變 length 長度或者超出設置,監聽都會失效。
性能問題,層級太深致使性能降低
因此 vue 在數組的原型方法上作了一些手腳 defineProperty(obj, 'push') 監聽 push 方法
檢測數組變化源碼解析:
1.Object.create(arrayPrototype)
初始化一個以數組原型對象 Array.prototype 爲參數的對象:Object.create(Array.prototype)
2.將該對象裏的全部數組方法用 definePrototype 重寫
3.在數據 observer 綁定的時候,判斷數據對象是否有 __proto__
,有就將數據直接綁定上重寫後的原型
4.若是瀏覽器不支持 __proto__
,依據原型鏈,就將重寫的原型直接掛在數據上好了。
5.這樣當調用數組 api 時,能夠通知依賴更新,若是數組包含引用類型,繼續遞歸遍歷監控
$set 原理:
若是目標是數組,直接使用數組的 splice 方法觸發相應式。
若是目標是對象,會先判讀屬性是否存在、對象是不是響應式。
最終若是要對屬性進行響應式處理,則是經過調用 defineReactive 方法進行響應式處理,最後通知訂閱 notify。
總結:對象和數組都是經過遞歸遍歷
vnode 對象是樹的遞歸遍歷
O(n^3) -> O(n)
觸發setter -> 觸發通知 notify -> 觸發 watcher 加進異步更新隊列,eventloop 會清空隊列,watcher 嘗試執行更新函數 -> 調用渲染函數,從新計算 vdom -> 進行 diff
代碼邏輯:
沒有舊節點,直接建立新的。
新舊 vnode 不一樣,直接銷燬舊的,建立新的。
新舊 vnode 相同,繼續比較子節點:
其中 vnode 爲文本節點,與舊不一樣則直接更新
子節點依舊是新舊之間的比較,只有新節點直接建立,只有舊節點則刪除舊的,新舊又不一樣,開始 diff 核心算法,重點講解:
while 循環比較新舊子節點:頭索引跟頭比較,尾跟尾,比完縮減往中間收攏,比較聽從:
頭與頭比較,相同則複用不做處理,同時頭++,尾、頭尾、尾頭的目的都是爲了複用
用 key 比較
map 表遍歷查找
剩餘節點,批量新增或刪除
總結:能不動就不動,不行就移動,最後處理新建或者刪除。相比React的Diff算法,一樣狀況下能夠減小移動節點次數,減小沒必要要的性能損耗,更加的優雅。
vdom:建立 vdom 的時候多了個 dynamicChildren 動態節點,patch 的時候只比對動態。
vue2 靜態節點也會 patch。
vdom:節點變動類型用 patchFlag 細分,用位掩碼組合,做爲斷定更新的依據。
vue2 若是是普通節點,會經過內置的update鉤子全量進行新舊對比,而後更新;若是是component,則會在prepatch階段進行判斷,有變化則會從新觸發forceUpdate,形成不少無用的重複對比。
diff 核心變化:用數組 map 記錄節點變動的位置以及新增的節點 + 最長子序列(若是遞增則位置不變)。
相同事件緩存不會從新生成。
vnode 對象是鏈表的循環遍歷,與遞歸不一樣的是能夠設置暫停和恢復,根據調度展開的優化代碼。
複用沒有變動的節點,用 key。
先比較兩棵樹的根節點,如果不一樣的類型,則直接銷燬舊的,重建新的。如果相同的類型,則看下 className、style 等是否相同,同時保留不變的狀態,比較完繼續對子節點遞歸,好比列表,在設置 key 的狀況下 diff 的開銷會更小 (沒有key的狀況下,在表頭插入將會重建,表尾只會添加)
MVC 相信這是絕大部分程序員最先接觸到的架構。
MVVM 雙向綁定:V 的變更,自動反映在 VM 上。V 和 M 不發生聯繫,其餘部分的通訊都是雙向的。
MVVM 框架目前存在的問題:執行效率,數據改變, UI 也會頻繁更新,引起子組件更新,性能不是最優。好消息是 Vue 3
已經解決了這個子組件重複渲染的問題,但需知沒有完美的解決方案,只有舍與得。
不少人沒有分清的是:ReactJs 實際上是一個單向數據流的 js 庫,狀態驅動視圖,是 MVC。而 React 全家桶是 MVP,近似 MVVM。
複製代碼
自己 C,P,VM 的邊界界定就十分模糊,不用鑽牛角尖,核心其實就是每一層專一於每一層的任務。如何對代碼進行組織管理,仍是要看需求來界定的,這也是框架架構模式不斷髮展的緣由。
這一道題,能夠說是上面的歸總,咱們能夠從大到小,從略到詳,從思想、生態、語法、數據、通訊、Diff、版本等角度來說,筆者整理了一些,如下挑幾個重點吧...
Vue 和 React
Vue3 和 React16 的區別
Vue3 和 React16 的類似處
Vue3 和 React16 總結
從輸入到渲染的整個流程?
流程裏每一個部分拿出來都能深挖,我認爲這道題很有道中三生萬物的韻味,前端的一切均可以從這裏開始,說白了 PC 的前端是被綁定在瀏覽器中的。
我本人本來對於渲染的這一塊,圖層和合成理解並不清晰,因而將這篇放這裏:爲何 CSS 動畫比 JS 高效
位移距離 × 位移影響的面積 < 0.1
知足這個公式便算體驗優秀,反例:小屏手機上忽然插入 dom 或廣告讓人膈應。瀏覽器緩存
掌握強緩存字段,協商緩存字段。
展開:除了常規的緩存手段,還能夠擴展下 1.代理緩存,2.V8 代碼緩存
HTTP
這一塊的內容是經過一些書籍和文章整理來的,記錄了一些容易混淆的點。
首先須要理清:http2 解決性能問題;http3 解決 http2 遺留問題;https 解決安全問題。
HTTP 加密算法
對稱加密
非對稱加密
傳統 RSA 握手:是 1. + 2. + 數字證書
結合(在交換密鑰環節使用公開密鑰加密方式,創建通訊交換報文階段使用共享密鑰加密方式)
TLS1.2 握手,與 3.
的區別在於 pre_random
的生成方式不一樣。
證書相關:
證書只解決了公鑰持有人究竟是誰。
原證書內容:簽發者、證書用途和基本信息、服務器公鑰、服務器加密算法、服務器 HASH 算法、證書的到期時間等。
原證書內容 + 最重要的防篡改的數字簽名 = 服務器發給客戶端的數字證書
數字簽名:對原證書內容進行 hash 函數(好比 SHA256)生成的摘要 digest(摘要表明服務器身份,能夠理解爲身份證),通過 CA 私鑰加密後生成數字簽名 signature,將數字簽名附在原證書末尾。這裏跟 JWT 很像。
客戶端收到數字證書,使用 CA 公鑰解密 signature 獲得 digest 驗明身份,再使用 hash 函數對證書原數據計算,獲得的結果與 digest 對比,徹底一致說明數據未被修改
放出《圖解 HTTP》原文用以確認:
服務器有本身的公鑰和私鑰,此時向 CA 申請證書,提交本身的公鑰及基自己份信息。
CA 也有本身的公鑰和私鑰,...用 CA 本身的私鑰...生成數字簽名,同時將服務器公鑰綁定入證書。這裏注意:CA 公鑰已經在咱們安裝瀏覽器的時候植入咱們機器了。
客戶端收到數字證書,先用瀏覽器內置的 CA 公鑰解密證書的數字簽名,獲得 hash 後的摘要,咱們假定叫作 hash_0
,而後咱們本身使用 hash 函數對證書內原報文進行計算,生成 hash_1
,二者一致便可確認服務器公鑰的真實性。
Q
:中間人是否會攔截髮送假證書到客戶端呢?
A
:由於證書的簽名是由服務器端網址等信息生成的,而且經過第三方機構的私鑰加密中間人沒法篡改; 因此最關鍵的問題是證書籤名的真僞。
還有 網絡安全
、4 種常見鏈接方式
、TCP 握手和揮手
、TCP 流量控制和擁塞控制
、HTTP 傳輸各類資源的表頭字段
、流與分段傳輸 (包括上傳和下載)
、TCP 序列號
等一堆重點。
擴展:
UDP 協議在遊戲場景使用較多,有 DTSL 保證安全,UDP 至關於 4 層的 IP 協議,方便上層協議的自定義和擴展。
https 握手證書驗證過程太耗費流量,同時因安全問題被禁止壓縮,且假如把 tls 只是當作一個技術參考,是能夠任意修改的,因而不少企業開始自定義內部協議,好比微信。
QUIC(Quick UDP Internet Connections)
基於UDP的傳輸層協議,提供像TCP同樣的可靠性。
直播協議:RTMP、HTTP-FLV、HLS
只有嚴格的工序、精確的用量才能保證甜品如咱們預期;只有不斷改進烘焙方式和花樣才能推陳出新,吸引更多顧客;只有好吃的甜品可以給人愉悅和幸福感。
完整的開發流程通常以下:
價值:你作的東西是否有價值?價值囊括不少方面。
推進力:企業所但願看到的,升職加薪的必要條件。
社區產出:提升你的社會影響力,可能創造無限可能的將來。這一塊大廠彷佛很看重,有沒有道友現身說法的 ?
就像簡歷中咱們所寫的:將某個項目的首屏加載提升了 x 倍,在 LCP、FID、CLS 等核心指標上又優化減小了多少秒;今天將軟件運行優化得趨於原生體驗;明天又產出了某個自研腳手架,提升 x 倍的開發效率;還有社區貢獻,影響力...這些都是價值,或者說亮點。
價值在企業招聘中,比重很大,關乎你的將來錢途。甚至間接影響你的身體情況。
別不信,舉個例子:程序員,避免不了天天面對新的需求,可是工做內容都是那樣,重複又重複,若是一味莽幹,免不了要加班、要禿頭,佔用多少本身的時間和生命?因此一個具備高價值、高優先級的東西,就是提效工具。
有些老油子可能會說:工做都那麼忙了,業務需求頻繁變動,哪來的時間?我只能輕蔑一笑,呵呵,時間如乳 go&%f3h,擠擠老是會有的。
一個提效工具能挽救多少業務、多少根頭髮,多少對情侶,相信幾年以後,諸君會深有體會。
總結:優先作重要不緊急的事情:我的/團隊規劃、提效工具/平臺創建、鍛鍊身體/我的影響力創建。事情是作不完的,只須要保證最重要的事情一直在被推動,不重要的能夠討論/推掉/改方案,最後還有一點,就是持續反思,反思可讓你進步飛快。
早些時候參加了個線下峯會,當時看着一羣大佬輪流在臺上技術分享,都是一些很是有意思的乾貨內容,整場下來個人狀態是:吃鯨...興奮...崇拜...
這就是前端嗎 ?i 了 i 了,因而額前綁上奮鬥的 「奮」,一頭莽進了這行。
轉眼 0202!
入行這幾年,大部分時光都是平淡無奇的,我原本就是個平凡、溫和、悶騷、鹹魚的人……常駐知乎、掘金等社區卻一直潛水不起一點波紋。
某個時刻,我閱讀到 神三元 的系列文章,起初以爲乾貨滿滿,嗯,這是個大佬,關注了,每次閱讀完他的文章我都淡定地喝一口茶,感受獲益良多。
疫情期間,他又有產出,我照例翻出一覽,良久,我喝了口茶,隨後眉頭一皺,頓覺不對,看下標題,春招?……噗!我震驚,不肯定,而後欣喜,沮喪……
這!這竟然是一個大三學生,我 &$%^@,大三就進了字節互娛架構組,了不得,恭喜你……
沒有比較就沒有傷害,想一想本身……emmm,原來我是個假前端!
神三元早早就明確了將來目標,就像他文章中說的,找到了痛點。而咱們大多數人直到工做了,還很迷茫。就像女生刷 Fit 視頻,看到視頻裏的健身達人曲線姣好的身材,羨慕不已。但看完視頻,卻只是簡單地在牀上翻了個身給予迴應,甚至還照常打開某團點了杯奶茶。
呵呵,我不想再這樣了,如今,先完成 那個 目標吧!
寫給將來的我和大家……