天天看點

2023前端開發知識總結歸納

js基礎

資料類型7+1

基本類型:number、string、undefined、boolean、null;

引用類型:Object;

基本類型添加了兩個新成員:symbol、BigInt;

基本類型和引用類型差別:前者按值通路,是以為我們操作的就是存儲在變量中的實際值;後者不能直接操作對象所在的記憶體空間,在操作對象時,實際操作的是該對象的引用。 基本類型存儲在棧中;引用類型的 ‘變量’名稱 存儲在棧中,同時存儲指針,該指針指向堆中的真實的值;(棧、堆概念可以直接搜尋 "js中棧和堆的概念和差別")

參考:阮一峰 ECMAScript 6 (ES6) 标準入門教程 第三版

參考書:犀牛書

this指向

箭頭函數:this繼承包裹箭頭函數的第一個普通函數中的this;

普通函數:new(this指向新對象)——bind/apply/call(this是強制指向的this)——this指向函數上下文對象——this指向window;

參考文章:juejin.cn/post/684490…

參考書:紅寶書

閉包

一個函數引用另外一個函數内部變量就會形成閉包,閉包在平時開發中非常的多見;了解作用域鍊建立和使用的細節對了解閉包非常重要;

參考文章:juejin.cn/post/684490…

參考書:紅寶書

原型

每個對象被建立開始,就與另一個對象關聯,從另一個對象上繼承其屬性,這裡的另一個對象就是原型;

原型存在的意義就是組成原型鍊。當範文一個對象屬性時,先從對象本身找,找不到就去對象原型上找,如果還找不到,就去對象原型的原型上找,如此類推,直到找到為止;這條由對象及原型組成的查找鍊條就是原型鍊;

參考文章:juejin.cn/post/684490…

參考書:紅寶書

繼承

組合繼承:通過 call修改子類this,将子類原型指向 new 父類(); 寄生組合繼承:通過 call 修改子類this,将子類原型指向父類原型(Object.create(父類.prototype)) ,并将子類原型構造函數指向子類;

參考書:紅寶書

子產品化

子產品化特點:複用性、可維護性; commonJs最早作為标準在NodeJs中引入, 作為NodeJs子產品化标準;在commonJs中,require首次加載就會執行整個腳本,在記憶體中生成一個對象緩存下來,下次加載時可直接從緩存擷取; 對于循環加載,隻輸出已執行的部分。還未執行部分不輸出; 最新ES6的 ES Module,是靜态加載;腳本被加載時,成為一個指向被加載子產品的引用,不會緩存;

并發和并行

差別:并發是兩個或多個事件在同一時間間隔内發生;并行是指兩個或多個事件在同一時刻内發生; 并行通過提升硬體能力,隻需要多核CPU即可達到; 并發中最常聽到的就是高并發,在一定時間,伺服器的吞吐量和QPS每秒響應請求數都是一定的。而在這樣的情況下,要解決高并發的問題,最簡單當然是提升機器性能,加記憶體,加硬碟,更新網速。當然,通過架構層面設計,也可以做點東西,部署多台機器,添加負載均衡層,将請求均勻;将資料庫分庫分表并讀寫分離;引入消息中間件等;緩存叢集引入;

異步方案

回調函數:在浏覽器端,異步問題就是Ajax網絡請求響應異步,而回調函數可以一定程度解決這個響應異步的問題,缺點是:不易維護、不易讀、不能直接return;

Generator:封裝多個内部狀态的異步解決方案,生成器函數;會傳回一個疊代器,配合next()函數,可以控制開始、暫停和恢複代碼; 場景:控制流管理、異步操作;

Promise:解決異步操作方案,包含異步操作結果的對象;内部存在三種狀态,一旦開始不可更改狀态;問題:無法取消,錯誤需要回調捕獲;Promise是鍊式調用,每次調用then之後傳回一個Promise,并且是一個全新的Promise; Promise實作依據Promise/A+規範—— 三種狀态:pedding、fulfilled、rejected; (Promise封裝的Ajax為例子)進行異步處理流:執行Promise回調函數,由于異步操作,内部狀态未變化。繼續執行then回調,内部狀态未變化,回調隊列中then回調暫時不執行。此時,異步執行完成(網絡請求響應),狀态變化,Promise内部調用resolve函數,回調隊列執行;

async/await:異步解決方案,需要配套使用;函數添加async後,函數會傳回一個Promise;await内部實作了Generator,await是異步操作,後來的表達式不傳回Promise的話,就會包裝成Promise.resolve(傳回值 ),然後去執行函數外的同步代碼;

事件循環

一個事件循環又一個貨多個任務隊列;一個任務隊列是一組任務;
1. 每個事件循環是一個正在運作的任務,它可以是一個任務或null;

2. 每個事件循環具有microtask隊列(微任務隊列),最初為空;

3. 每個事件循環都有一個執行微任務檢查點的布爾值,該布爾值最初為false;
複制代碼           

1. js的事件循環如何環執行?

浏覽器事件循環執行順序:

首先執行script腳本同步代碼,屬于宏任務; 當執行完目前所有同步任務後,執行棧為空,查詢是否有異步任務代碼需要執行; 執行目前宏任務下的所有微任務; 微任務執行完之後,如有必要會渲染頁面; 然後開始下一輪事件循環;

2. 宏任務和微任務有哪些?

宏任務:script、setTimeout、setInterval、setImmediate、I/O、UI Render; 微任務:process.nextTick、promise、MutationObsever;

3. Nodejs的事件循環和浏覽器事件循環差別?

Nodejs和浏覽器端,宏任務和微任務交替執行,調用順序基本相同。Nodejs執行會進行階段區分,分為6個階段:參考:Node.js 事件循環文檔,每進入某個階段,會從回調隊列中取出函數執行。當隊列為空或回調函數達到系統設定門檻值,就進入下一個階段。

異步方案

可以把ajax異步回調作為浏覽器端的最初的異步解決方案,異步回調 ———> Promise執行個體 ——> Generator ——> async/await,大緻是一個這樣的線,我們需要關注的可能主要就是Promise 和 async/await的方案。

1. Promise内部實作了解嘛?它的具體工作流程是怎麼樣的?

Promise是異步解決方案,包含異步操作結果的對象,特點:内部存在三種狀态,狀态一旦變化不可更改狀态;Promise是鍊式調用,每次調用then回調函數都會傳回一個新的Promise,并且是一個全新的Promise; Promise異步處理流:執行Promise執行個體回調函數,由于異步請求或者操作,此時狀态未變化。繼續執行then回調,由于狀态未變化回調會被放入回調數組中。直到Promise執行個體中異步請求或者操作完成,狀态發生變化,調用resolve函數,回調數組周遊執行,then回調函數拿到相關資料。

2. 說一說async/await

參考:

Promise原了解析

圖解Promise流程

浏覽器渲染原理

浏覽器是多程序應用,每打開一個Tab頁,就相當于建立了一個獨立的浏覽器程序。浏覽器程序有:Browser程序(主程序)、插件程序、GPU程序、渲染程序(浏覽器核心)。主程序隻有一個是負責協調應用,同時預設每個Tab頁面一個渲染程序,互不影響。我們常說的Js線程、GUI渲染線程就包含在渲染程序之中,還包括異步http請求線程、事件觸發線程等。

1. 位址欄輸入域名位址之後發生了什麼?

1. DNS服務查詢域名對應的目标服務IP位址;
2. 根據目标IP位址查找到目标伺服器,并建立TCP連接配接;
3. 伺服器響應傳回資料或文本資訊等;
4. 用戶端擷取到資料之後進行頁面渲染;
複制代碼           

2. 浏覽器渲染的流程?

1. 請求html檔案處理html标記建構DOM樹;
2. 請求css檔案處理css标記建構CSSOM樹;
3. 将DOM和CSSOM合并成一個渲染樹;
4. 根據渲染樹布局,以計算每個節點的幾何資訊;
5. 将各節點繪制在螢幕上;
複制代碼           

存在阻塞的css資源時,浏覽器會延遲JS的執行和DOM的建構;

3. 重繪和回流?

重繪是當節點需要更改外觀而不影響布局;回流是布局或幾何屬性需要改變;

參考:渲染性能

參考:

從浏覽器多程序到JS單線程

你不知道的浏覽器頁面渲染機制

網絡協定

2023前端開發知識總結歸納

關于TCP和UDP的介紹、TCP的三次握手和四次揮手就不細說,相關文章可以參考:傳輸層協定TCP和UDP ,TCP三向交握和四次揮手;

http協定是常用的網絡傳輸協定,全稱是超文本傳輸協定,它規定了http請求和響應的具體結構,當然還包含其他東西,例如:緩存、檔案類型、參數、請求類型、狀态等。它是建立在傳輸層TCP協定之上的,TCP握手成功之後,才可以進行網絡資料傳輸。

HTTP/HTTPS

1. 什麼是http協定?它是怎麼樣的?

http是TCP/IP協定應用層協定,主要負責資料或文本圖檔等内容的傳輸,它是建立在傳輸層TCP協定之上的。http分為請求封包和響應封包,從Web用戶端發往Web伺服器的HTTP封包稱為請求封包(request message)。從伺服器發往用戶端的封包稱為響應封包,封包分為:起始行、 首部字段、主體等;

2. http和https的差別?

http和https從字面的差別就是一個s,這個s就是SSL/TCL加密協定。說到加密協定就繞不開加密技術,在SSL/TCL加密協定中既有用到非對稱加密,也有用到對稱加密。SSL/TCL加密協定相當于是在應用層和傳輸層之間加了一層,可稱為加密層。 大緻流程:用戶端向伺服器端索要加密證書擷取公鑰等證書資訊;雙方協商生成"對話密鑰";雙方采用"對話密鑰"進行加密通信。非對稱加密保證"對話密鑰"的安全傳輸,對稱加密保證用戶端和服務端對資料的加解密。

3. http網絡緩存如何配置?

如果需要開啟強緩存和協商緩存,可在服務端nginx web伺服器進行對應的配置,開啟對應的網絡緩存。其他服務端web伺服器也可配置。(配置細節網上一大堆)

4. 強緩存和協商緩存的差別?

強緩存:Cache-Control,常用屬性有max-age、no-cache、no-store等。max-age表示相對時間内的緩存,在這個相對時間内不會再去請求對應資源;no-cache表示不意味着不緩存,它的意思是在使用緩存資源之前,它必須經過伺服器的檢查; no-store表示不緩存。

協商緩存:Last-modified 和 ETag,這兩個類似,可以了解為檔案辨別。也可以将ETag(你選擇的版本ID)或者Last-modified日期添加到響應首部中。用戶端下次擷取資源時,他會分别通過If-None-Match(與ETage對應)和If-Modified-Since(與Last-Mofied對應)兩個請求首部将值發送給伺服器。如果伺服器發現兩次值都是對等的,就是傳回一個HTTP 304。它們之間的差別:ETag 隻要資源變化,它就會改變;Last-modified 不識别秒機關裡的修改。

如何使用 ————— 前端中保證HTML資源是最新的,設定如:max-age=300、ETag、Last-modified,當然也可考慮使用no-cache、ETag、Last-modified配合。而CSS和JS找資源已經被注入到HTML中,資源檔案位址通常使用哈希值加入檔案名中保證資源是最新,css和js檔案可設定:max-age=31536000或last-modified 配合使用。

5. 了解http2.0嘛?為什麼說http2.0更好?

http2.0基于二進制分幀層,http2.0可以在共享TCP連接配接的基礎上同時發送請求和響應。在http1.x中,是通過文本的方式傳輸資料,基于文本的方式傳輸資料存在很多缺陷,文本的表現形式有多樣性,是以要做到健壯性考慮的場景必然有很多,但是二進制則不同,隻有0和1的組合,是以選擇了二進制傳輸,實作友善且健壯。

為了保證http不受影響,那就需要在應用層(HTTP2.0)和傳輸層(TCP or UDP)之間增加一個二進制分幀層。在二進制分幀層上,http2.0會将所有傳輸的資訊分為更小的消息和幀,并采用二進制格式編碼,其中http1.x的首部資訊會被封裝到Headers幀,而Request Body則封裝到Data幀。在傳輸中會共用一個TCP流(TCP連接配接中的一個虛拟通道,可以承載雙向的消息),不至于重複連接配接。

參考:

書籍:HTTP權威指南

SSL/TLS協定運作機制的概述

前端架構

前端架構目前市面主流就是React和Vue,對于架構的使用和學習,前期建議多翻翻文檔,中期根據自己在使用過程中遇到的問題學習,後期就可以考慮翻源碼了。由于工作原因,我對react了解更多,是以分享主要就是React。 React和Vue作為前端架構在本質上做的是相同的事,在浏覽器和開發操作之間加了一個中間層,來進項目的輔助管理和開發。

React架構

1. JSX本質是什麼,它和JS的關系是什麼?為什麼使用JSX?

JSX是類HTML的文法結構,實質是JS的文法擴張。它文法結構簡潔,通俗易懂,對于研發效率和體驗有大的提升。

2. JSX背後的功能子產品是什麼,這個功能子產品做了哪些事情?

JSX通過babel文法轉換之後,實際就是通過React.createElement函數來建立React元素。createElement接收三個參數type類型,config配置,children子元素。通過createElement就可建立出虛拟DOM對象。

3. react16.3新舊生命周期,消失的舊生命周期有哪些?

去掉ComponentWillMount和CompoentWillReceiveProps 更新為getDeicvedStateFromProps,保證生命周期更加單一,更可控;去掉ComponentWillUpdate新增getSnapshotDeforeUpdate;

4. React團隊為什麼要去掉舊的生命周期函數?

React16+引入Fiber架構,Fiber會将一個大的更新任務拆解為多個小任務,而且它是可中止,可恢複的。React16+生命周期被劃分為render和commit兩個階段。render階段在執行過程中允許被打斷,而commit階段操作涉及真實DOM渲染,是不可打斷的。

`ComponentWillMount`、
`ComponentWillUpdate`、
`ComponentWillReceiveProps`
複制代碼           

這些生命周期,它們都處于render階段,而在Fiber架構中,render階段會被打斷,重複被執行。在這些生命周期可能習慣做的事情可能有:setState、異步請求、操作真實DOM等。而在Fiber異步渲染控制下,這些生命周期可能會導緻非常嚴重的bug(例如在這些廢棄的生命周期中調用支付接口)。

5. React元件資料如何流動?實作資料通信的方案有哪些?

react是自上而下的單向元件資料流

1.父-子元件通過prop屬性傳遞資料,子-父元件可通過函數;
2.兄弟元件共享同一個父元件,達到兄弟元件通信;
3.Context API實作全局通信;(目前還沒試過)
4.redux資料狀态容,進行可預測的狀态管理;
5.釋出/訂閱模式實作任意元件通信;
複制代碼           

6. 為什麼是React Hooks?

相對于Class元件,函數元件更加輕量,更加符合UI=render(data)特點。同時在Fiber架構的加持下,Hooks的實作不是問題。配合函數元件的發展,Hooks應運而生,進而是函數元件真正把資料和渲染綁定到一起。當然Hooks也還是存在部分不足:部分周期不存在;不能很好的消化“複雜”,元件的拆分群組織是一個大的挑戰,不易把握。

7. 為什麼Hooks執行順序如此重要?

Hooks本質是連結清單。例如 使用useText、useState建立state時,hook建立的state會以單連結清單形式儲存,更新時,函數元件重新調用,hooks會依次周遊單連結清單,讀取資料并更新,這一過程完全按照建立時的順序來的。是以當更新時,位置一旦改變,執行順序被替換,運作就會出現bug。

8. 調和(協調)和diff的關系或差別?

調和指的是虛拟DOM映射到真實DOM的過程。調和過程并不能和diff畫等号。調和是“使一緻”的過程,而diff是“找不同”的過程,它隻是“使一緻”過程中的一個環節。(當然常說的調和相關問題多半就是diff過程的)

9. react的diff邏輯和思路?

1.因為時間複雜度的原因,diff過程隻針對同層的節點作比較;
2.對于同類型的元件,才有進一步對比的必要性;
3.對于清單元件,通過key屬性來維持節點的穩定性,避免總是生産新節點;
複制代碼           

10. setState的工作流是怎麼樣的?

非并發(concurrent)模式:setState會出現異步和同步的現象。在生命周期和合成事件中是同步,而在setTimeout、setInterval、DOM原生函數等函數中是同步的。那麼這是為什麼尼?在合成事件或生命周期執行時,批量更新的任務鎖就被開啟了,我們所做的setState操作會被放入到批量更新隊列中,直到函數執行完,批量更新的任務鎖才會被關閉。批量更新的任務鎖是一個同步操作,而一旦你在setTimeout函數使用setState,此時setTimeout函數回調會被放入下一個宏任務執行,而當setState執行時,批量更新的任務鎖時關閉的,它就不會放入到批量更新隊列中,而是直接執行。

并發(concurrent)模式:setState不會出現異步和同步的現象。因為存在時間切片,隻要目前時間片沒有結束,依舊可以将多個 setState 合并成一個,即使是在setTimeout中被調用。而對于超過目前時間片的操作,會通過MessageChannel放入到下一個宏任務中繼續執行。(MessageChannel接收消息的時機比 Promise 所在的 microTask 要晚,但是早于 setTimeout)

11. Stack Reconciler棧調和 有怎麼樣的局限性?

浏覽器中Js線程和渲染線程是互斥的。這兩個線程不能穿插執行,必須串行。而當Js線程長時間占用主線程,那麼渲染線程的更新就不得不長時間的等待,這時就會導緻頁面卡頓。

Stack Reconciler棧調和是一個同步遞歸過程,虛拟DOM樹diff算法周遊是深度優先周遊。由于它是同步的,不可在被打斷。當處理結構複雜,體量龐大的虛拟DOM樹時,Stack Reconciler時間會很長,以為這Js主線程長時間占用主線程,進而導緻上述中說道的渲染卡頓/頁面卡死。

12. 說一說Fiber架構?

特點:可中斷、可恢複、存在優先級。

Scheduler ————> Reconciler ————> Renderer
 更新優先級         找不同         渲染不同
複制代碼           

在Fiber架構模式下,每個更新任務會被賦予一個優先級。當然有任務A進入排程器,這個任務優先級更高,而Reconciler中已有任務B在執行,那麼,Reconciler會将任務B終止,更高優先級的任務A被推入Reconciler。當A任務完成之後,新一輪排程會将之前中斷的任務B重新推入Reconciler,繼續它的渲染之旅。

render開始 ——————> (工作單元| 工作單元 | 工作單元) ——————> commit送出渲染
複制代碼           

13. ReactDOM.render調用棧的初始化階段、render階段

初始化階段:會建立root對象這個對象挂載_internalRoot屬性,而_internalRoot也就是FiberRoot。FiberRoot的本質是一個FiberRootNode對象,其中包含current屬性,current對象是一個FiberNode執行個體。current對象就是一個Fiber節點,并是Fiber樹的頭部節點;确定Fiber的優先級,結合優先級建立目前Fiber的update對象,并将其入隊排程FiberRoot;接下來進入render階段;(此時相當于隻有一個Fiber頭部節點)

render階段:通過createWorkInProgress函數,建立rootFiber節點的副本workInProgress節點樹(即current節點的副本節點),他們通過alternate互相引用;接着會觸發beginWork函數,進而實作對新的Fiber節點的建立。循環周遊,元件元素Fiber會不斷被建立(每個元素節點對應一個Fiber節點),直到建立到最後一個為止,此時Fiber樹(單連結清單)基本完成;

重點: 此時已經周遊到了單連結清單的最底部節點,然後會由下自上的依次生成真實DOM節點,同時被它的父元件副作用鍊,這個副作用鍊也是一個單連結清單,直周遊到根節點,此時的根節點上的副作用鍊就包含的全部的DOM更新。那麼剩下的隻需要拿到root下的副作用鍊更新即可了。

參考:

修言 深入淺出搞定 React

React 架構的演變 - 從同步到異步

React 架構的演變 - 從遞歸到循環

React 架構的演變 - 更新機制

React 架構的演變 - Hooks 的實作

性能優化

可使用Chrome Lighthouse進行性能測評,根據測評結果也可以得出一些改進的點: react架構層面可以做的優化方向核心點:減少重新 render 的次數;減少計算的量,主要是減少重複計算。有下列具體方案:

1. 拆分公共元件和業務元件,根據具體業務分離,降低元件顆粒度;
2. shouldComponentUpdate中攔截非不要渲染;
3. 對于簡單的資料類型,可考慮使用React.PureComponent;
4. 函數元件考慮使用React.meno,React.memo 與 React.PureComponent 非常相似;(版本React 16.6.0)
5. React Hooks元件使用useCallback緩存函數,避免每次傳回一個新的函數;(版本React v16.8)
6. React Hooks元件使用useMemo緩存計算值;(版本React v16.8)
複制代碼           

一個前端項目下通用的優化技巧:使用緩存、節流、壓縮、按需加載、全局管理等方法或技巧。如下:

1. 避免頻繁渲染更新,即使必須的情況下,也需要考慮是否使用節流函數;
2. 對于長清單頁面,考慮翻頁加載、點選下一頁或者虛拟長清單,避免資料量過大,渲染卡頓;
3. 統一控制項目中的定時器函數,避免定時器偷跑;
4. 拆分Js檔案,可考慮按需加載,提升加載速度;
5. 保證首屏必要資料渲染,可增加過渡圖檔,提升使用者體驗;
6. 對于後端接口多餘資料可考慮清洗資料,隻保留必要資料;
7. 避免過多的資料請求,可考慮使用資料緩存,提升使用者體驗;
8. 對于大圖考慮CDN圖檔加載,也可考慮圖檔懶加載;
9. 避免使用過多css選擇器嵌套;
10. 代碼檔案gzip壓縮等,伺服器相關緩存配置;
複制代碼           

以上更多的是各種技巧和原則,如果要知道具體的标準,可以參考google為Web性能表現提供的文檔developers.google.cn/Web Performance

設計模式

參考文章: JavaScript設計模式: https://www.yuque.com/yopai/pp6bv5/mtu8xy