當前位置:首頁 » 網頁前端 » 前端虛擬緩存
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

前端虛擬緩存

發布時間: 2023-06-17 15:03:44

⑴ 對於開發一個java項目,怎麼樣提高它的速度、安全性、穩定性.哪些基本的

基礎的就是那些。
1.代碼優化 //寫的不安全的代碼,或者性能低下的。
2.資料庫優化//資料庫的分庫分表等
3.虛擬機優化//優化虛擬機參數
4.緩存//包含前端緩存以及業務緩存,資料庫緩存等。
5.負載均衡及集群//增加穩定性和負載
6.前端頁面優化。//優化客戶載入時間,提高效率
7.靜態化//同上
等等。暫時想到這么多。。

⑵ 前端經典面試題(包含JS、CSS、React、瀏覽器等)

防抖

節流

誤區:我們經常說get請求參數的大小存在限制,而post請求的參數大小是無限制的。

實際上HTTP 協議從未規定 GET/POST 的請求長度限制是多少。對get請求參數的限制是來源與瀏覽器或web伺服器,瀏覽器或web伺服器限制了url的長度。為了明確這個概念,我們必須再次強調下面幾點:

補充補充一個get和post在緩存方面的區別:

可從IIFE、AMD、CMD、CommonJS、UMD、webpack(require.ensure)、ES Mole、

vue和react都是採用diff演算法來對比新舊虛擬節點,從而更新節點。在vue的diff函數中(建議先了解一下diff演算法過程)。在交叉對比中,當新節點跟舊節點 頭尾交叉對比 沒有結果時,會根據新節點的key去對比舊節點數組中的key,從而找到相應舊節點(這里對應的是一個key => index 的map映射)。如果沒找到就認為是一個新增節點。而如果沒有key,那麼就會採用遍歷查找的方式去找到對應的舊節點。一種一個map映射,另一種是遍歷查找。相比而言。map映射的速度更快。vue部分源碼如下:

創建map函數

遍歷尋找

在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修改為true,而當React在調用事件處理函數之前就會調用這個batchedUpdates,造成的後果,就是由React控制的事件處理過程setState不會同步更新this.state

虛擬dom相當於在js和真實dom中間加了一個緩存,利用dom diff演算法避免了沒有必要的dom操作,從而提高性能。

具體實現步驟如下:

用 JavaScript 對象結構表示 DOM 樹的結構;然後用這個樹構建一個真正的 DOM 樹,插到文檔當中

當狀態變更的時候,重新構造一棵新的對象樹。然後用新的樹和舊的樹進行比較,記錄兩棵樹差異

把2所記錄的差異應用到步驟1所構建的真正的DOM樹上,視圖就更新了。

結構:display:none: 會讓元素完全從渲染樹中消失,渲染的時候不佔據任何空間, 不能點擊, visibility: hidden:不會讓元素從渲染樹消失,渲染元素繼續占據空間,只是內容不可見,不能點擊 opacity: 0: 不會讓元素從渲染樹消失,渲染元素繼續占據空間,只是內容不可見,可以點擊

繼承:display: none:是非繼承屬性,子孫節點消失由於元素從渲染樹消失造成,通過修改子孫節點屬性無法顯示。visibility: hidden:是繼承屬性,子孫節點消失由於繼承了hidden,通過設置visibility: visible;可以讓子孫節點顯式。

性能:displaynone : 修改元素會造成文檔迴流,讀屏器不會讀取display: none元素內容,性能消耗較大 visibility:hidden: 修改元素只會造成本元素的重繪,性能消耗較少讀屏器讀取visibility: hidden元素內容 opacity: 0 :修改元素會造成重繪,性能消耗較少

聯系:它們都能讓元素不可見

常用的一般為三種 .clearfix , clear:both , overflow:hidden ;

比較好是 .clearfix ,偽元素萬金油版本,後兩者有局限性.

clear:both :若是用在同一個容器內相鄰元素上,那是賊好的,有時候在容器外就有些問題了, 比如相鄰容器的包裹層元素塌陷

overflow:hidden :這種若是用在同個容器內,可以形成 BFC 避免浮動造成的元素塌陷

概念:將多個小圖片拼接到一個圖片中。通過 background-position 和元素尺寸調節需要顯示的背景圖案。

優點:

缺點:

block 元素特點:

1.處於常規流中時,如果 width 沒有設置,會自動填充滿父容器 2.可以應用 margin/padding 3.在沒有設置高度的情況下會擴展高度以包含常規流中的子元素 4.處於常規流中時布局時在前後元素位置之間(獨佔一個水平空間) 5.忽略 vertical-align

inline 元素特點

1.水平方向上根據 direction 依次布局

2.不會在元素前後進行換行

3.受 white-space 控制

4. margin/padding 在豎直方向上無效,水平方向上有效

5. width/height 屬性對非替換行內元素無效,寬度由元素內容決定

6.非替換行內元素的行框高由 line-height 確定,替換行內元素的行框高由 height , margin , padding , border 決定 7.浮動或絕對定位時會轉換為 block 8. vertical-align 屬性生效

GIF :

JPEG

PNG

七種數據類型

(ES6之前)其中5種為基本類型: string , number , boolean , null , undefined ,

ES6出來的 Symbol 也是原始數據類型 ,表示獨一無二的值

Object 為引用類型(范圍挺大),也包括數組、函數,

輸出結果是:

工廠模式

簡單的工廠模式可以理解為解決多個相似的問題;

單例模式

只能被實例化(構造函數給實例添加屬性與方法)一次

沙箱模式

將一些函數放到自執行函數裡面,但要用閉包暴露介面,用變數接收暴露的介面,再調用裡面的值,否則無法使用裡面的值

發布者訂閱模式

就例如如我們關注了某一個公眾號,然後他對應的有新的消息就會給你推送,

代碼實現邏輯是用數組存貯訂閱者, 發布者回調函數裡面通知的方式是遍歷訂閱者數組,並將發布者內容傳入訂閱者數組

1.字面量

2.Object構造函數創建

3.使用工廠模式創建對象

4.使用構造函數創建對象

HTML中與javascript交互是通過事件驅動來實現的,例如滑鼠點擊事件onclick、頁面的滾動事件onscroll等等,可以向文檔或者文檔中的元素添加事件偵聽器來預訂事件。想要知道這些事件是在什麼時候進行調用的,就需要了解一下「事件流」的概念。

什麼是事件流:事件流描述的是從頁面中接收事件的順序,DOM2級事件流包括下面幾個階段。

addEventListener addEventListener 是DOM2 級事件新增的指定事件處理程序的操作,這個方法接收3個參數:要處理的事件名、作為事件處理程序的函數和一個布爾值。最後這個布爾值參數如果是true,表示在捕獲階段調用事件處理程序;如果是false,表示在冒泡階段調用事件處理程序。

IE只支持事件冒泡

獲取一個對象的原型,在chrome中可以通過__proto__的形式,或者在ES6中可以通過Object.getPrototypeOf的形式。

那麼Function.proto是什麼么?也就是說Function由什麼對象繼承而來,我們來做如下判別。

我們發現Function的原型也是Function。

我們用圖可以來明確這個關系:

這里來舉個栗子,以 Object 為例,我們常用的 Object 便是一個構造函數,因此我們可以通過它構建實例。

則此時, 實例為instance , 構造函數為Object ,我們知道,構造函數擁有一個 prototype 的屬性指向原型,因此原型為:

這里我們可以來看出三者的關系:

在 JS 中,繼承通常指的便是 原型鏈繼承 ,也就是通過指定原型,並可以通過原型鏈繼承原型上的屬性或者方法。

在函數式編程中,函數是一等公民。那麼函數柯里化是怎樣的呢?

函數柯里化指的是將能夠接收多個參數的函數轉化為接收單一參數的函數,並且返回接收餘下參數且返回結果的新函數的技術。

函數柯里化的主要作用和特點就是參數復用、提前返回和延遲執行。

在一個函數中,首先填充幾個參數,然後再返回一個新的函數的技術,稱為函數的柯里化。通常可用於在不侵入函數的前提下,為函數 預置通用參數 ,供多次重復調用。

call 和 apply 都是為了解決改變 this 的指向。作用都是相同的,只是傳參的方式不同。

除了第一個參數外, call 可以接收一個參數列表, apply 只接受一個參數數組。

bind 和其他兩個方法作用也是一致的,只是該方法會返回一個函數。並且我們可以通過 bind 實現柯里化。

如何實現一個 bind 函數

對於實現以下幾個函數,可以從幾個方面思考

如何實現一個call函數

如何實現一個apply函數

箭頭函數其實是沒有 this 的,這個函數中的 this 只取決於他外面的第一個不是箭頭函數的函數的 this 。在這個例子中,因為調用 a 符合前面代碼中的第一個情況,所以 this 是 window 。並且 this 一旦綁定了上下文,就不會被任何代碼改變。

在函數中,我們首先使用 var 關鍵字聲明了 name 變數。這意味著變數在創建階段會被提升( JavaScript 會在創建變數創建階段為其分配內存空間),默認值為 undefined ,直到我們實際執行到使用該變數的行。我們還沒有為 name 變數賦值,所以它仍然保持 undefined 的值。

使用 let 關鍵字(和 const )聲明的變數也會存在變數提升,但與 var 不同,初始化沒有被提升。在我們聲明(初始化)它們之前,它們是不可訪問的。這被稱為「暫時死區」。當我們在聲明變數之前嘗試訪問變數時, JavaScript 會拋出一個 ReferenceError 。

關於 let 的是否存在變數提升,我們何以用下面的例子來驗證:

let 變數如果不存在變數提升, console.log(name) 就會輸出 ConardLi ,結果卻拋出了 ReferenceError ,那麼這很好的說明了, let 也存在變數提升,但是它存在一個「暫時死區」,在變數未初始化或賦值前不允許訪問。

變數的賦值可以分為三個階段:

關於 let 、 var 和 function :

依次輸出:undefined -> 10 -> 20

答案: D

colorChange 方法是靜態的。靜態方法僅在創建它們的構造函數中存在,並且不能傳遞給任何子級。由於 freddie 是一個子級對象,函數不會傳遞,所以在 freddie 實例上不存在 freddie 方法:拋出 TypeError 。

1.使用第一次push,obj對象的push方法設置 obj[2]=1;obj.length+=1 2.使用第二次push,obj對象的push方法設置 obj[3]=2;obj.length+=1 3.使用console.log輸出的時候,因為obj具有 length 屬性和 splice 方法,故將其作為數組進行列印 4.列印時因為數組未設置下標為 0 1 處的值,故列印為empty,主動 obj[0] 獲取為 undefined

undefined {n:2}

首先,a和b同時引用了{n:2}對象,接著執行到a.x = a = {n:2}語句,盡管賦值是從右到左的沒錯,但是.的優先順序比=要高,所以這里首先執行a.x,相當於為a(或者b)所指向的{n:1}對象新增了一個屬性x,即此時對象將變為{n:1;x:undefined}。之後按正常情況,從右到左進行賦值,此時執行a ={n:2}的時候,a的引用改變,指向了新對象{n:2},而b依然指向的是舊對象。之後執行a.x = {n:2}的時候,並不會重新解析一遍a,而是沿用最初解析a.x時候的a,也即舊對象,故此時舊對象的x的值為{n:2},舊對象為 {n:1;x:{n:2}},它被b引用著。後面輸出a.x的時候,又要解析a了,此時的a是指向新對象的a,而這個新對象是沒有x屬性的,故訪問時輸出undefined;而訪問b.x的時候,將輸出舊對象的x的值,即{n:2}。

在比較相等性,原始類型通過它們的值進行比較,而對象通過它們的引用進行比較。 JavaScript 檢查對象是否具有對內存中相同位置的引用。

我們作為參數傳遞的對象和我們用於檢查相等性的對象在內存中位於不同位置,所以它們的引用是不同的。

這就是為什麼 { age: 18 } === { age: 18 } 和 { age: 18 } == { age: 18 } 返回 false 的原因。

所有對象鍵(不包括 Symbols )都會被存儲為字元串,即使你沒有給定字元串類型的鍵。這就是為什麼 obj.hasOwnProperty(Ƈ') 也返回 true 。

上面的說法不適用於 Set 。在我們的 Set 中沒有 「1」 : set.has(Ƈ') 返回 false 。它有數字類型 1 , set.has(1) 返回 true 。

這題考察的是對象的鍵名的轉換。

catch 塊接收參數 x 。當我們傳遞參數時,這與變數的 x 不同。這個變數 x 是屬於 catch 作用域的。

之後,我們將這個塊級作用域的變數設置為 1 ,並設置變數 y 的值。現在,我們列印塊級作用域的變數 x ,它等於 1 。

在 catch 塊之外, x 仍然是 undefined ,而 y 是 2 。當我們想在 catch 塊之外的 console.log(x) 時,它返回 undefined ,而 y 返回 2 。

⑶ 前端虛擬化 後端雙存儲HA構建方案

微軟方案不太清楚。
如果用VMWARE方案,可以做Storage HA。
軟體要企業增強版,授權可能比較貴。
你可以到VMWARE網站查找相關資料。

⑷ Web前端工程師的入門指南-教你如何成為一名web前端開發工程師

今天小編要跟大家分享的文章是關於Web前端工程師的入門指南-教你如何成為一名web前端開發工程師。經過如此多的試驗和測試,而不是說你從頭開始創建了所有內容,接著,你在網頁上創建了第一個登錄表單時,你感覺如何?經過了多次更改後,將布局分配給第一個Web應用程序時感覺如何?當成功處理了數千個用戶的操作時,你感覺如何?

大多數Web開發人員都經歷了上述所有階段,最初可能會對其中某些感到沮喪,但是當他們看到自己的網站正在運行並且人們在世界各地使用它時,總體感覺確實令人興奮和驚奇。Web開發人員負責許多任務,從收集需求到設計網站,處理網站的後端部分,並使其成功地為用戶服務。每年,行業中都會涌現出新技術和工具,以提高開發人員的工鄭槐作效率,並為用戶提供更好的網站。對於他們來說,保持在Web開發游戲之上的挑戰變得越來越大。今天,我們將討論要在2020年成為Web開發人員的完整地圖。這將是針對所有開發人員(前端,後端和全棧)的實用指南。


1、首先確定你的目標或道路


我們將討論很多技術,趨勢和工具,但我們不希望您不知所措,因此你需要首先決定要成為一名Web開發人員要做什麼,因為這將幫助你選擇合適的工具。和學習技術。成為Web開發人員的原因有很多,下面列出了一些選擇因素:


·你想作為一卜叢賀名Web開發型派人員在一家公司工作,這是最普遍的原因。


·你想以自由開發人員的身份來開始自己的業務或代理。


·你可以成為其他公司的顧問。


·你可以創建自己的應用來賺錢。


·編碼是你的業余愛好。


從上述感興趣或目標的領域,你可以選擇適用於你的目標的正確工具和技術。如果你的目標是成為一名前端開發人員,則可以選擇前端開發的工具和技術。後端和全棧開發也是如此。


2、Web開發的基本工具和軟體


·
計算機和操作系統:如果沒有計算機和操作系統,則無法編寫代碼。要學習Web開發,你不需要任何高端計算機(如果你擁有的話,那麼更好)。你可以使用任何類型的中型筆記本電腦或台式機。對於操作系統,可以使用適合你的MacOS,Windows(最新版本)或Linux。


·文本編輯器/
IDE:毫無疑問,VSCode適用於大多數情況和大多數語言。它具有良好的性能,出色的擴展性,內置的終端功能以及大量功能。在2019年StackOverFlow調查中,VSCode也是開發人員的首選。你還可以選擇其他一些不錯的選擇,例如Sublime
Text或Atom。如果我們談論IDE,那麼是Visual
Studio(#或C#),Eclipse和Netbeans(Java)。是不錯的選擇。


·
Web瀏覽器:大多數開發人員的首選是Chrome或Firefox。Chrome速度很快,並且使用V8引擎(JavaScript引擎)。Firefox也取得了長足的進步,其中的一些好東西不在chrome瀏覽器中。兩種瀏覽器都有出色的開發工具,可以對Web開發中的問題進行故障排除。


·終端:您將使用一些系統命令來使用CLI進行很多工作。您可以將默認或第三方終端用於您的Web開發項目。Bash,Zsh,Powershell,Git
Bash,iTerm,Hyper這些都是可以使用的選項。


·設計(可選):並不是每個人都需要學習。在公司中,有專門的團隊來製作圖像,徽標或草圖,但是如果您是自由職業者,則可能必須學習Adobe
XD,Photoshop,Sketch或Figma。


3、從HTML和CSS開始


HTML和CSS是Web開發的基本構建塊。無論您的Web應用程序有多先進,或者使用什麼框架和後端語言,都必須使用HTML和CSS構建前端應用程序。因此,這是在Web開發中要學習的第一件事。


·HTML5(語義元素,屬性,文檔類型等)


·CSS基礎知識顏色,字體,位置,盒子模型等。


·CSSGrid和Flexbox對齊內容或創建列。


·CSS自定義屬性


4、響應式布局


您的應用程序應該在所有類型的設備(例如智能手機,平板電腦,台式機,iPad或任何其他屏幕尺寸的設備)上都可以查看和使用。因此,了解創建響應式設計或布局非常重要。讓我們來看一些重要的主題。


·了解如何設置視口


·媒體查詢不同的屏幕尺寸。


·流體寬度


·雷姆單位


·移動優先


5、自定義可重用CSS組件


與其依賴大型的CSS框架(如Bootstrap),不如創建自己的模塊化,可重用的CSS組件以在項目中使用。如果您構建自己的定製設計,則無需導入完整的庫。您創建只需要特定UI的組件。的新趨勢最近還出現了有助於更有效地編寫CSS代碼的代碼。如果你已經了解CSS,那麼您無需在學習Saas上花費很多精力。Saas是CSS預處理程序,可為標准CSS添加更多功能並使其更加高效。你可以使用變數,嵌套,條件語句來減少CSS的重復並提高其效率。你還可以為每個可重用組件創建單獨的Saas文件。Sass確實節省了很多時間,所以你絕對應該在2020年學習它。


6、CSS框架


學習CSS框架的普及程度不如去年,但對於不擅長設計的開發人員而言,仍然非常相關或有用。有許多流行的CSS框架可供使用,其中一些如下。


·Bootstrap是最流行的CSS框架。學習引導程序也有助於學習其他框架。


·Tailwind
CSS是其他正在流行的框架,與其他框架幾乎沒有什麼不同。它是一組實用程序類,因此您可以創建自己的按鈕和其他看起來與其他按鈕確實不同的東西。它們也是高度可定製的。


·物化


·布爾瑪


7、前端必須語言:JavaScript


學習HTML和CSS之後,接下來需要學習的是Vanilla
Javascript。對開發人員來說,掌握javascript基本知識非常重要。您將在伺服器端語言(例如PHP,Python或#)中使用大量javascript,並且如果您想與React,Angular,NodeJS,Vue或任何其他javascript框架或庫一起使用,則非常需要學習這種語言。以下是你應該在javascript中涵蓋的一些重要主題


·JavaScript基礎知識(變數,數據類型,函數,條件等)


·DOM(文檔對象模型)


·JSON(JavaScript對象表示法)


·提取API(請求/響應/Ajax)


·如果您想轉向React,Vue,Angular或其他框架,現代JS(ES6)概念對於學習非常重要。


8、一些重要工具


Web開發中將使用一些工具。這些工具將幫助你進行調試,提高生產率,管理代碼,與其他開發人員合作以及類似的東西。讓我們討論其中一些工具。


·
Git(版本控制)和Github是您肯定會在2020年學習的最受歡迎的工具。Git在與其他開發人員協作和管理代碼方面有很多幫助。您還可以選擇其他一些選項,例如GitLab,Bitbucket和其他一些選項。


·
了解如何使用瀏覽器開發工具。無論是chrome還是firefox,您都應該知道如何使用不同的選項卡,例如元素選項卡,javascript控制台,用於請求和響應的網路選項卡,應用程序選項卡以及其他用於不同目的的選項卡。


·大多數IDE或文本編輯器都具有添加擴展名或插件的功能,這對提高生產力和構建Web應用程序非常有幫助。例如,Visual
Studio代碼中的VSCode擴展可幫助下載擴展,例如實時伺服器或實時saas編譯器以與React一起使用。


·Emmet是另一個很棒的工具,它允許您編寫非常快速的HTML和CSS,這有助於提高開發人員的生產力。


·
學習使用javascript軟體包管理器,例如NPM和Yarn。如果您正在使用Javascript框架或庫(例如React),那麼這些軟體包管理器將使用很多,但是對於其他語言(例如Python或Php),您將使用不同的軟體包管理器。


·
如果要在前端安裝NPM軟體包,則必須使用Webpack或Parcel。如果要創建自己的模塊,或者要將一個javascript文件帶到另一個javascript文件,則默認情況下不能僅使用瀏覽器來執行此操作,因此需要Webpack或Parcel對其進行捆綁。


9、基本部署


此時,一旦你知道應該為前端開發學習什麼工具或技術,就需要知道如何在Internet上部署前端網站。如果你正在為小型企業構建一些小型應用程序,登錄頁面或個人站點,則無需學習AWS或DevOps,僅因為它們具有光澤和新潮。你將使事情變得更加復雜而不是簡單。你需要在2020年學習一些部署工具和步驟。


·域注冊(Namecheap,Google等)


·託管託管(InMotion,Hostgator,Bluehost等)


·靜態主機(Netlify,Github頁面)


·SSL證書。


·FTP,SFTP(文件傳輸協議)非常適合小型應用程序。


·SSH(安全外殼),用於高級應用程序。


·CLI和Git。


到目前為止,我們討論的任何工具,技術趨勢或步驟都是前端開發的一部分。您尚不知道該框架,但可以為個人和小型企業構建網站,也可以構建適合移動設備的布局。您還可以使用到目前為止討論的工具或技術來部署小型應用程序或項目。如果您想申請工作,那麼學習一些前端框架(如React,Vue或Angular)將是很棒的。


10、前端框架和狀態管理


框架使您可以進行更高級的前端開發。框架為您提供了許多優勢,例如可重用的組件,更有條理的UI或頁面交互。這對於協作更好,也有助於編寫簡潔的代碼。另外,了解狀態管理。每個框架都有不同的方法。以下是2020年的一些流行框架和狀態管理器。


·React:React庫是最流行的Web開發學習方法,與其他框架和庫相比,它相當容易。React開發人員還有很多工作要做。您可以將Rex和
ContextAPI與Hooks一起使用以進行狀態管理。


·Vue:
Vue也越來越受歡迎,開發人員也更喜歡學習Vue。與React和Angular相比,Vue最容易學習。VueX是為視圖而構建的狀態管理器。


·Angular:此框架通常在大型組織中使用。它具有相當陡峭的學習曲線。用Angular學習
TypeScript也很好。它允許您使用可選的靜態類型並支持ES2015的功能。NGRX和Services是可以學習此框架的良好狀態管理器。


可選學習:


·
如果您具有這三個框架之一的知識,那麼您還可以使用Svelte,它是一個JavaScript編譯器,可讓您生成純凈的原始JS代碼並幫助您輕松構建用戶界面。


·
了解伺服器端渲染。NextJS(React)和NuxtJS(Vue)是允許您在伺服器上運行React和Vue的框架。兩者都有很好的功能,例如更好的SEO,文件系統路由,自動代碼拆分,靜態導出,JS中的CSS和許多其他功能。


·靜態網站生成器:Gatsby(反應式)和Gridsome(Vue)


我們已經討論了所有大多數前端開發工具和技術。現在讓我們討論成為後端開發人員或全棧開發人員的語言和技術。


11、伺服器端語言(選擇一種)


您應該至少了解一種伺服器端語言。要在2020年選擇一種語言,下面提供了一些選項...


·NodeJS(不是語言,而是運行時環境)


·Python(非常適合初學者)


·Java(適合大型組織)


·Php(適合自由職業)


·Ruby(2020年少兩極)


·C#


·Go


注意:無論你喜歡學習哪種伺服器端語言,都要確保你了解使用該語言的數據結構和演算法。數據結構和演算法將幫助您為用戶呈現數據,並將幫助您優化Web應用程序中的代碼。我們特別建議您專注於使用數組和字元串(最重要)。你將同時使用這兩種方法。


12、伺服器端框架(選擇一項)


一旦學習了自己選擇的一種伺服器端語言,就可以使用其中一種語言框架。您可以選擇以下給出的選項之一...


·Node.js_Express,Koa,Adonis,Feather.js,Nest.js


·Python:Django,Flask,


·Java:SpringMVC,Grails


·PHP:Laravel,Symfony,Codeignitor,Slim


·Ruby:Sinatra上的RubyonRails


·C#:ASP.NETMVC


·Go:Revel


13、資料庫(選擇一項)


大多數Web應用程序都需要一個存儲數據的地方。在某些情況下,某些技術或某些語言可以與某些資料庫配合使用。例如:在Mern堆棧中,M代表MongoDB,而在LAMP堆棧中M代表MySQL,但完全取決於您要為應用程序選擇哪個資料庫。我們將討論2020年一些流行的資料庫。


·關系資料庫:RDBMS仍然是最受歡迎的資料庫。最喜歡使用PostgreSQL,MySQL,MSSQL。


·NoSQL:MongoDB,RethinkDB,CouchDB


·雲資料庫:Firebase,AzureCouldDB,AWS


·輕量級和緩存:Redis,SQLlite,NeDB


在學習資料庫時,您還將學習RDBMS,ORM(對象關系映射器)或ODM(對象數據映射器)的SQL(結構化查詢語言)。GraphQL
:(可選)您可以了解現在流行的GraphQL。這是API的查詢語言。它具有類似於JSON的簡單語法,並且相當容易實現。


14、CMS:內容管理


您絕對應該了解內容管理系統,尤其是如果您是自由職業者。CMS用於將內容添加到您的網站或應用程序。客戶能夠更新自己的內容非常好。


·
傳統CMS:WordPress(PHP),Drupal(PHP),Keystone(Javascript),Enro(Javascript)


·其他CMS:DEDECMS,帝國CMS,PHPcms,Prismic.io,Strati。


15、部署和DevOps


託管全棧應用程序或後端應用程序比僅前端應用程序要復雜一些,尤其是當您擁有資料庫時。確保您知道如何使用CLI進行部署。了解有關用於部署應用程序的以下內容。


在大多數公司中,有不同的團隊從事DevOps的工作。因此,擁有有關DevOps的知識完全是可選的。您可以了解到,如果您正在從事自己的項目。


·SSH(安全外殼)


·Web伺服器環境:NGINX,Apache


·應用程序託管:Linode,Heroku,AWS,Azure,Now。


·虛擬化:Docker,Vagrant


·測試:單元,功能,集成等


·負載平衡,監視,安全性。


以上所有技術工具都足以使您成為前端,後端或全棧開發人員。根據最終目標選擇正確的工具和技術。


以上就是小編今天為大家分享的關於Web前端工程師的入門指南-教你如何成為一名web前端開發工程師的文章,希望本篇文章能夠對正在從事web前端工作的小夥伴和正在學習web前端知識的夥伴們有所幫助,想要了解更多web前端相關知識記得關注北大青鳥web培訓官網。最後祝願小夥伴們工作順利,成為一名優秀的web前端開發工程師!


英文|#/how-to-become-a-web-developer-in-2020-a-complete-guide/翻譯|web前端開發(ID:web_qdkf)


⑸ 最全從輸入URL到瀏覽器顯示頁面都發生了什麼前端瀏覽器渲染流程

首先了解一下URL的組成:

從上面的URL可以看出,一個完整的URL包括以下幾部分:

1、協議部分:該URL的協議部分為「http:」,這代表網頁使用的是HTTP協議。在Internet中可以使用多種協議,如HTTP,FTP等等本例中使用的是HTTP協議。在"HTTP"後面的「//」為分隔符

2、域名部分:該URL的域名部分為「www..com」。一個URL中,也可以使用IP地址作為域名使用

3、埠部分:跟在域名後面的是埠,域名和埠之間使用「:」作為分隔符。埠不是一個URL必須的部分,如果省略埠部分,將採用默認埠80

4、虛擬目錄部分:從域名後的第一個「/」開始到最後一個「/」為止,是虛擬目錄部分。虛擬目錄也不是一個URL必須的部分。本例中的虛擬目錄是「/news/」

5、文件名部分:從域名後的最後一個「/」開始到「?」為止,是文件名部分,如果沒有「?」,則是從域名後的最後一個「/」開始到「#」為止,是文件部分,如果沒有「?」和「#」,那麼從域名後的最後一個「/」開始到結束,都是文件名部分。本例中的文件名是「index.asp」。文件名部分也不是一個URL必須的部分,如果省略該部分,則使用默認的文件名

6、錨部分:從「#」開始到最後,都是錨部分。本例中的錨部分是「name」。錨部分也不是一個URL必須的部分

7、參數部分:從「?」開始到「#」為止之間的部分為參數部分,又稱搜索部分、查詢部分。本例中的參數部分為「boardID=5&ID=24618&page=1」。參數可以允許有多個參數,參數與參數之間用「&」作為分隔符。

很多大公司面試喜歡問這樣一道面試題, 輸入URL到看見頁面發生了什麼? ,今天我們來總結一下。 簡單來說,共有以下幾個過程

下面我們來看看具體的細節

輸入 www.google.com 網址後,首先在本地的域名伺服器中查找,沒找到去根域名伺服器查找,沒有再去 com 頂級域名伺服器查找,,如此的類推下去,直到找到IP地址,然後把它記錄在本地,供下次使用。大致過程就是 . -> .com -> google.com. -> www.google.com. 。 (你可能覺得我多寫 .,並木有,這個.對應的就是根域名伺服器,默認情況下所有的網址的最後一位都是.,既然是默認情況下,為了方便用戶,通常都會省略,瀏覽器在請求DNS的時候會自動加上)

既然已經懂得了解析的具體過程,我們可以看到上述一共經過了N個過程,每個過程有一定的消耗和時間的等待,因此我們得想辦法解決一下這個問題!

DNS存在著多級緩存,從離瀏覽器的距離排序的話,有以下幾種: 瀏覽器緩存,系統緩存,路由器緩存,IPS伺服器緩存,根域名伺服器緩存,頂級域名伺服器緩存,主域名伺服器緩存。

在你的chrome瀏覽器中輸入:chrome://dns/,你可以看到chrome瀏覽器的DNS緩存。

系統緩存主要存在/etc/hosts(Linux系統)中

檢查瀏覽器是否有緩存

通過 Cache-Control 和 Expires 來檢查是否命中強緩存,命中則直接取本地磁碟的html(狀態碼為200 from disk(or memory) cache,內存or磁碟);


如果沒有命中強緩存,則會向伺服器發起請求(先進行下一步的TCP連接),伺服器通過 Etag 和 Last-Modify 來與伺服器確認返回的響應是否被更改(協商緩存),若無更改則返回狀態碼(304 Not Modified),瀏覽器取本地緩存;


若強緩存和協商緩存都沒有命中則返回請求結果。

不知道你們有沒有注意這樣一件事,你訪問http://.com的時候,每次響應的並非是同一個伺服器(IP地址不同),一般大公司都有成百上千台伺服器來支撐訪問,假設只有一個伺服器,那它的性能和存儲量要多大才能支撐這樣大量的訪問呢?DNS可以返回一個合適的機器的IP給用戶,例如可以根據每台機器的負載量,該機器離用戶地理位置的距離等等,這種過程就是DNS負載均衡

TCP 協議通過三次握手建立連接。

翻譯成大白話就是:

為什麼是3次? :避免 歷史 連接,確認客戶端發來的請求是這次通信的人。
為什麼不是4次? :3次夠了第四次浪費

建立連接的過程是利用客戶伺服器模式,假設主機A為客戶端,主機B為伺服器端。

採用三次握手是為了防止失效的連接請求報文段突然又傳送到主機B,因而產生錯誤。失效的連接請求報文段是指:主機A發出的連接請求沒有收到主機B的確認,於是經過一段時間後,主機A又重新向主機B發送連接請求,且建立成功,順序完成數據傳輸。考慮這樣一種特殊情況,主機A第一次發送的連接請求並沒有丟失,而是因為網路節點導致延遲達到主機B,主機B以為是主機A又發起的新連接,於是主機B同意連接,並向主機A發回確認,但是此時主機A根本不會理會,主機B就一直在等待主機A發送數據,導致主機B的資源浪費。

採用兩次握手不行,原因就是上面說的失效的連接請求的特殊情況。而在三次握手中, client和server都有一個發syn和收ack的過程, 雙方都是發後能收, 表明通信則准備工作OK.

為什麼不是四次握手呢? 大家應該知道通信中著名的藍軍紅軍約定, 這個例子說明, 通信不可能100%可靠, 而上面的三次握手已經做好了通信的准備工作, 再增加握手, 並不能顯著提高可靠性, 而且也沒有必要。

第一次握手

客戶端發送syn包(Seq=x)到伺服器,並進入SYN_SEND狀態,等待伺服器確認;

第二次握手:

伺服器收到syn包,必須確認客戶的SYN(ack=x+1),同時自己也發送一個SYN包(Seq=y),即SYN+ACK包,此時伺服器進入SYN_RECV狀態;

第三次握手:

客戶端收到伺服器的SYN ACK包,向伺服器發送確認包ACK(ack=y+1),此包發送完畢,客戶端和伺服器進入ESTABLISHED狀態,完成三次握手。

握手過程中傳送的包里不包含數據,三次握手完畢後,客戶端與伺服器才正式開始傳送數據。理想狀態下,TCP連接一旦建立,在通信雙方中的任何一方主動關閉連接之前,TCP 連接都將被一直保持下去。

要先申請CA證書,並安裝在伺服器上(一個文件,配置nginx支持監聽443埠開啟ssl並設置證書路徑)

瀏覽器發送請求;

網站從瀏覽器發過來的加密規則中選一組自身也支持的加密演算法和hash演算法,並向瀏覽器發送帶有公鑰的證書,當然證書還包含了很多信息,如網站地址、證書的頒發機構、過期時間等。

瀏覽器解析證書。

驗證證書的合法性。如頒發機構是否合法、證書中的網站地址是否與訪問的地址一致,若不合法,則瀏覽器提示證書不受信任,若合法,瀏覽器會顯示一個小鎖頭。

若合法,或用戶接受了不合法的證書,瀏覽器會生成一串隨機數的密碼(即密鑰),並用證書中提供的公鑰加密。

使用約定好的hash計算握手消息,並使用生成的隨機數(即密鑰)對消息進行加密,最後將之前生成的所有消息一並發送給網站伺服器。

網站伺服器解析消息。用已有的私鑰將密鑰解密出來,然後用密鑰解密發過來的握手消息,並驗證是否跟瀏覽器傳過來的一致。然後再用密鑰加密一段握手消息,發送給瀏覽器。

瀏覽器解密並計算握手消息的HASH,如果與服務端發來的HASH一致,此時握手過程結束,之後所有的通信數據將由之前瀏覽器生成的隨機密碼並利用對稱加密演算法進行加密。這里瀏覽器與網站互相發送加密的握手消息並驗證,目的是為了保證雙方都獲得了一致的密碼,並且可以正常的加密解密數據,為後續真正數據的傳輸做一次測試。

發送HTTP請求
首先科補一個小知識,HTTP的埠為80/8080,而HTTPS的埠為443

發送HTTP請求的過程就是構建HTTP請求報文並通過TCP協議中發送到伺服器指定埠 請求報文由 請求行 請求抱頭 請求正文 組成。
請求行
請求行的格式為 Method Request-URL HTTP-Version CRLF eg: GET index.html HTTP/1.1 常用的方法有: GET , POST , PUT , DELETE , OPTIONS , HEAD 。
常見的請求方法區別
這里主要展示 POST 和 GET 的區別
常見的區別

注意一點你也可以在GET裡面藏body,POST裡面帶參數

重點區別

GET 會產生一個 TCP 數據包,而 POST 會產生兩個 TCP 數據包。
詳細的說就是:

注意一點,並不是所有的瀏覽器都會發送兩次數據包,Firefox就發送一次

請求報頭
請求報頭允許客戶端向伺服器傳遞請求的附加信息和客戶端自身的信息。

從圖中可以看出,請求報頭中使用了Accept, Accept-Encoding, Accept-Language, Cache-Control, Connection, Cookie等欄位。Accept用於指定客戶端用於接受哪些類型的信息,Accept-Encoding與Accept類似,它用於指定接受的編碼方式。Connection設置為Keep-alive用於告訴客戶端本次HTTP請求結束之後並不需要關閉TCP連接,這樣可以使下次HTTP請求使用相同的TCP通道,節省TCP連接建立的時間。

請求正文
當使用POST, PUT等方法時,通常需要客戶端向伺服器傳遞數據。這些數據就儲存在請求正文中。在請求包頭中有一些與請求正文相關的信息,例如: 現在的Web應用通常採用Rest架構,請求的數據格式一般為json。這時就需要設置 Content-Type: application/json 。
更重要的事情-HTTP緩存
HTTP屬於客戶端緩存,我們常認為瀏覽器有一個緩存資料庫,用來保存一些靜態文件,下面我們分為以下幾個方面來簡單介紹HTTP緩存

緩存的規則
緩存規則分為 強制緩存 協商緩存


強制緩存
當緩存資料庫中有客戶端需要的數據,客戶端直接將數據從其中拿出來使用(如果數據未失效),當緩存伺服器沒有需要的數據時,客戶端才會向服務端請求。

又稱對比緩存。客戶端會先從緩存資料庫拿到一個緩存的標識,然後向服務端驗證標識是否失效,如果沒有失效服務端會返回304,這樣客戶端可以直接去緩存資料庫拿出數據,如果失效,服務端會返回新的數據

強制緩存
對於強制緩存,伺服器響應的header中會用兩個欄位來表明——Expires和Cache-Control。


Expires
Exprires的值為服務端返回的數據到期時間。當再次請求時的請求時間小於返回的此時間,則直接使用緩存數據。但由於服務端時間和客戶端時間可能有誤差,這也將導致緩存命中的誤差,另一方面,Expires是HTTP1.0的產物,故現在大多數使用Cache-Control替代。


Cache-Control
Cache-Control有很多屬性,不同的屬性代表的意義也不同。

協商緩存
協商緩存需要進行對比判斷是否可以使用緩存。瀏覽器第一次請求數據時,伺服器會將緩存標識與數據一起響應給客戶端,客戶端將它們備份至緩存中。再次請求時,客戶端會將緩存中的標識發送給伺服器,伺服器根據此標識判斷。若未失效,返回304狀態碼,瀏覽器拿到此狀態碼就可以直接使用緩存數據了。
對於協商緩存來說,緩存標識我們需要著重理解一下,下面我們將著重介紹它的兩種緩存方案。
Last-Modified
Last-Modified:伺服器在響應請求時,會告訴瀏覽器資源的最後修改時間。

從字面上看,就是說:從某個時間節點算起,是否文件被修改了

這兩個的區別是一個是修改了才下載一個是沒修改才下載。
Last-Modified 說好卻也不是特別好,因為如果在伺服器上,一個資源被修改了,但其實際內容根本沒發生改變,會因為Last-Modified時間匹配不上而返回了整個實體給客戶端(即使客戶端緩存里有個一模一樣的資源)。為了解決這個問題,HTTP1.1推出了Etag。


Etag
Etag:伺服器響應請求時,通過此欄位告訴瀏覽器當前資源在伺服器生成的唯一標識(生成規則由伺服器決定)

但是實際應用中由於Etag的計算是使用演算法來得出的,而演算法會佔用服務端計算的資源,所有服務端的資源都是寶貴的,所以就很少使用Etag了。


緩存的優點

不同刷新的請求執行過程
瀏覽器地址欄中寫入URL,回車

F5

Ctrl+F5

伺服器處理請求並返回HTTP報文
它會對TCP連接進行處理,對HTTP協議進行解析,並按照報文格式進一步封裝成HTTP Request對象,供上層使用。這一部分工作一般是由Web伺服器去進行,我使用過的Web伺服器有Tomcat, Nginx和Apache等等 HTTP報文也分成三份, 狀態碼 響應報頭 響應報文


狀態碼
狀態碼是由3位數組成,第一個數字定義了響應的類別,且有五種可能取值:

平時遇到比較常見的狀態碼有:200, 204, 301, 302, 304, 400, 401, 403, 404, 422, 500
常見狀態碼區別
200 成功
請求成功,通常伺服器提供了需要的資源。
204 無內容
伺服器成功處理了請求,但沒有返回任何內容。
301 永久移動
請求的網頁已永久移動到新位置。 伺服器返回此響應(對 GET 或 HEAD 請求的響應)時,會自動將請求者轉到新位置。
302 臨時移動
伺服器目前從不同位置的網頁響應請求,但請求者應繼續使用原有位置來進行以後的請求。
304 未修改
自從上次請求後,請求的網頁未修改過。 伺服器返回此響應時,不會返回網頁內容。
400 錯誤請求
伺服器不理解請求的語法。
401 未授權
請求要求身份驗證。 對於需要登錄的網頁,伺服器可能返回此響應。
403 禁止
伺服器拒絕請求。
404 未找到
伺服器找不到請求的網頁。
422 無法處理
請求格式正確,但是由於含有語義錯誤,無法響應
500 伺服器內部錯誤
伺服器遇到錯誤,無法完成請求。
響應報頭
常見的響應報頭欄位有: Server, Connection...。
響應報文
你從伺服器請求的HTML,CSS,JS文件就放在這裡面

就是 Webkit 解析渲染頁面的過程。

這個過程涉及兩個比較重要的概念 迴流 重繪 ,DOM結點都是以盒模型形式存在,需要瀏覽器去計算位置和寬度等,這個過程就是迴流。等到頁面的寬高,大小,顏色等屬性確定下來後,瀏覽器開始繪制內容,這個過程叫做重繪。瀏覽器剛打開頁面一定要經過這兩個過程的,但是這個過程非常非常非常消耗性能,所以我們應該盡量減少頁面的迴流和重繪

這個過程中可能會有dom操作、ajax發起的http網路請求等。

web-socket、ajax等,這個過程通常是為了獲取數據

setTimeout、setInterval、Promise等宏任務、微任務隊列

當Render Tree中部分或全部元素的尺寸、結構、或某些屬性發生改變時,瀏覽器重新渲染部分或全部文檔的過程稱為迴流。

會導致迴流的操作:

一些常用且會導致迴流的屬性和方法:

當頁面中元素樣式的改變並不影響它在文檔流中的位置時(例如:color、background-color、visibility等),瀏覽器會將新樣式賦予給元素並重新繪制它,這個過程稱為重繪。

JS的解析是由瀏覽器的JS引擎完成的。由於JavaScript是單線程運行,也就是說一個時間只能幹一件事,干這件事情時其他事情都有排隊,但是有些人物比較耗時(例如IO操作),所以將任務分為 同步任務 非同步任務 ,所有的同步任務放在主線程上執行,形成執行棧,而非同步任務等待,當執行棧被清空時才去看看非同步任務有沒有東西要搞,有再提取到主線程執行,這樣往復循環(冤冤相報何時了,阿彌陀佛),就形成了Event Loop事件循環,下面來看看大人物

先看一段代碼

結果我想大家都應該知道。主要來介紹JavaScript的解析,至於Promise等下一節再說

JavaScript是一門單線程語言,盡管H5中提出了 Web-Worker ,能夠模擬實現多線程,但本質上還是單線程,說它是多線程就是扯淡。

既然是單線程,每個事件的執行就要有順序,比如你去銀行取錢,前面的人在進行,後面的就得等待,要是前面的人弄個一兩個小時,估計後面的人都瘋了,因此,瀏覽器的JS引擎處理JavaScript時分為 同步任務 非同步任務

這張圖我們可以清楚看到

js引擎存在monitoring process進程,會持續不斷的檢查主線程執行棧是否為空,一旦為空,就會去Event Queue那裡檢查是否有等待被調用的函數。 估計看完這些你對事件循環有一定的了解,但是事實上我們看對的沒這么簡單,通常我們會看到Promise,setTimeout,process.nextTick(),這個時候你和我就懵逼。

不同任務會進入不同的任務隊列來執行。 JS引擎開始工作後,先在宏任務中開始第一次循環( script裡面先執行,不過我喜歡把它拎出來,直接稱其進入執行棧 ),當主線程執行棧全部任務被清空後去微任務看看,如果有等待執行的任務,執行全部的微任務(其實將其回調函數推入執行棧來執行),再去宏任務找最先進入隊列的任務執行,執行這個任務後再去主線程執行任務(例如執行```console.log("hello world")這種任務),執行棧被清空後再去微任務,這樣往復循環(冤冤相報何時了)

下面來看一段代碼

我們看看它的執行情況

具體的執行過程大致就是這樣。


⑹ web前端diff 演算法深入一下

有同學問:能否詳細說一下 diff 演算法。

詳細的說,請閱讀這篇文章,有疑問的地方歡迎留言一起討論。

因為 diff 演算法是 vue2.x , vue3.x 以及 react 中關鍵核心點,理解 diff 演算法,更有助於理解各個框架本質。

說到「diff 演算法」,不得不說「虛擬 Dom」,因為這兩個息息相關。

比如:

等等

我們先來說說虛擬 Dom,就是通過 JS 模擬實現 DOM ,接下來難點就是如何判斷舊對象和新對象之間的差異。

Dom 是多叉樹結構,如果需要完整的對比兩棵樹的差異,那麼演算法的時間復雜度 O(n ^ 3),這個復雜度很難讓人接收,尤其在 n 很大的情況下,於是 React 團隊優化了演算法,實現了 O(n) 的復雜度來對比差異。

實現 O(n) 復雜度的關鍵就是只對比同層的節點,而不是跨層對比,這也是考慮到在實際業務中很少會去跨層的移動 DOM 元素。

虛擬 DOM 差異演算法的步驟分為 2 步:

實際 diff 演算法比較中,節點比較主要有 5 種規則的比較

部分源碼 https://github.com/vuejs/vue/blob//src/core/vdom/patch.js#L501 如下:

在 reconcileChildren 函數的入參中

diff 的兩個主體是:oldFiber(current.child)和 newChildren(nextChildren,新的 ReactElement),它們是兩個不一樣的數據結構。

部分源碼

很多時候手工優化 dom 確實會比 virtual dom 效率高,對於比較簡單的 dom 結構用手工優化沒有問題,但當頁面結構很龐大,結構很復雜時,手工優化會花去大量時間,而且可維護性也不高,不能保證每個人都有手工優化的能力。至此,virtual dom 的解決方案應運而生。

virtual dom 是「解決過多的操作 dom 影響性能」的一種解決方案。

virtual dom 很多時候都不是最優的操作,但它具有普適性,在效率、可維護性之間達到平衡。

virutal dom 的意義:

vue2.x 的 diff 位於 patch.js 文件中,該演算法來源於 snabbdom,復雜度為 O(n)。了解 diff 過程可以讓我們更高效的使用框架。react 的 diff 其實和 vue 的 diff 大同小異。

最大特點:比較只會在同層級進行, 不會跨層級比較。

對比之前和之後:可能期望將 直接移動到

的後邊,這是最優的操作。

但是實際的 diff 操作是:

vue 中也使用 diff 演算法,有必要了解一下 Vue 是如何工作的。通過這個問題,我們可以很好的掌握,diff 演算法在整個編譯過程中,哪個環節,做了哪些操作,然後使用 diff 演算法後輸出什麼?

解釋:

mount 函數主要是獲取 template,然後進入 compileToFunctions 函數。

compileToFunction 函數主要是將 template 編譯成 render 函數。首先讀取緩存,沒有緩存就調用 compile 方法拿到 render 函數的字元串形式,在通過 new Function 的方式生成 render 函數。

compile 函數將 template 編譯成 render 函數的字元串形式。後面我們主要講解 render

完成 render 方法生成後,會進入到 mount 進行 DOM 更新。該方法核心邏輯如下:

上面提到的 compile 就是將 template 編譯成 render 函數的字元串形式。核心代碼如下:

compile 這個函數主要有三個步驟組成:

分別輸出一個包含

parse 函數:主要功能是 將 template 字元串解析成 AST(抽象語法樹) 。前面定義的 ASTElement 的數據結構,parse 函數就是將 template 里的結構(指令,屬性,標簽) 轉換為 AST 形式存進 ASTElement 中,最後解析生成 AST。

optimize 函數(src/compiler/optomizer.js):主要功能是 標記靜態節點 。後面 patch 過程中對比新舊 VNode 樹形結構做優化。被標記為 static 的節點在後面的 diff 演算法中會被直接忽略,不做詳細比較。

generate 函數(src/compiler/codegen/index.js):主要功能 根據 AST 結構拼接生成 render 函數的字元串

其中 genElement 函數(src/compiler/codgen/index.js)是根據 AST 的屬性調用不同的方法生成字元串返回。

總之:

就是 compile 函數中三個核心步驟介紹,

patch 函數 就是新舊 VNode 對比的 diff 函數,主要是為了優化 dom,通過演算法使操作 dom 的行為降低到最低, diff 演算法來源於 snabbdom,是 VDOM 思想的核心。snabbdom 的演算法是為了 DOM 操作跨級增刪節點較少的這一目標進行優化, 它只會在同層級進行,不會跨層級比較。

總的來說:

在創建 VNode 就確定類型,以及在 mount/patch 的過程中採用位運算來判斷一個 VNode 的類型,在這個優化的基礎上再配合 Diff 演算法,性能得到提升。

可以看一下 vue3.x 的源碼:https://github.com/vuejs/vue/blob//src/core/vdom/patch.js

對 oldFiber 和新的 ReactElement 節點的比對,將會生成新的 fiber 節點,同時標記上 effectTag,這些 fiber 會被連到 workInProgress 樹中,作為新的 WIP 節點。樹的結構因此被一點點地確定,而新的 workInProgress 節點也基本定型。在 diff 過後,workInProgress 節點的 beginWork 節點就完成了,接下來會進入 completeWork 階段。

snabbdom 演算法:https://github.com/snabbdom/snabbdom

定位:一個專注於簡單性、模塊化、強大功能和性能的虛擬 DOM 庫。

snabbdom 中定義 Vnode 的類型(https://github.com/snabbdom/snabbdom/blob//src/vnode.ts#L12)

init 函數的地址:

https://github.com/snabbdom/snabbdom/blob//src/init.ts#L63

init() 函數接收一個模塊數組 moles 和可選的 domApi 對象作為參數,返回一個函數,即 patch() 函數。

domApi 對象的介麵包含了很多 DOM 操作的方法。

源碼:

https://github.com/snabbdom/snabbdom/blob//src/init.ts#L367

源碼:

https://github.com/snabbdom/snabbdom/blob//src/h.ts#L33

h() 函數接收多種參數,其中必須有一個 sel 參數,作用是將節點內容掛載到該容器中,並返回一個新 VNode。

在 vue2.x 不是完全 snabbdom 演算法,而是基於 vue 的場景進行了一些修改和優化,主要體現在判斷 key 和 diff 部分。

1、在 snabbdom 中 通過 key 和 sel 就判斷是否為同一節點,那麼在 vue 中,增加了一些判斷 在滿足 key 相等的同時會判斷,tag 名稱是否一致,是否為注釋節點,是否為非同步節點,或者為 input 時候類型是否相同等。

https://github.com/vuejs/vue/blob//src/core/vdom/patch.js#L35

2、diff 差異,patchVnode 是對比模版變化的函數,可能會用到 diff 也可能直接更新。

https://github.com/vuejs/vue/blob//src/core/vdom/patch.js#L404