關于http的問題
1.常見Http請求頭

host (主機和埠號)
Accept (傳輸檔案型別)
Content-Type(表示具體請求中的媒體型別資訊)
Origin(表示請求出處,防止CSRF的攻擊)
Upgrade-Insecure-Requests (升級為 HTTPS 請求)
User-Agent (瀏覽器名稱)
Referer (頁面跳轉處)
Accept-Encoding(檔案編解碼格式)
Cookie (Cookie)
x-requested-with :XMLHttpRequest (是 Ajax 異步請求)
到了http2.0協議是小寫字母,這點跟HTTP1不同,
另外部分新增的協議用冒號開頭

:authority(應該和host一樣,顯示域名)
:method(請求型別)
:path(請求介面)
:scheme(協議)

2.介紹Http2.0
官網:https://http2.github.io/
http協議是互聯網上使用最廣泛、最通用的通訊協議,也可以說是互聯網通訊協議的事實標準,http/2是http規范的一個最新版本
HTTP2的核心是性能優化,主要是延時和帶寬兩方面,與HTTP1.X相比的優勢在于:
低延時, 多路復用(一個域名一個連接)避免了連接頻繁創建和慢啟動程序;服務端推送(Server Push)實作了資源“預讀”,提前將資源推送到客戶端,
帶寬占用少, 頭部壓縮技術及二進制協議減少了對帶寬的資源占用

多路復用:多個請求可同時在一個連接上并行執行,某個請求任務耗時嚴重,不會影響到其它連接的正常執行
頭部壓縮:hpack演算法對header進行壓縮
Server push :服務器傳送
3.tcp三次握手,四次揮手
欄位 含義
URG 緊急指標是否有效,為1,表示某一位需要被優先處理
ACK 確認號是否有效,一般置為1,
PSH 提示接收端應用程式立即從TCP緩沖區把資料讀走,
RST 對方要求重新建立連接,復位,
SYN 請求建立連接,并在其序列號的欄位進行序列號的初始值設定,建立連接,設定為1
FIN 希望斷開連接,
---------------------
SYN_SENT 客戶端狀態
SYN_RECV半連接狀態
ESTABLISHED表示兩臺機器正在傳輸資料
FIN-WAIT-1終止等待狀態
FIN-WAIT-2半關閉狀態
CLOSE-WAIT(關閉等待)狀態
LAST-ACK(最后確認)狀態
TIME-WAIT(時間等待)狀態
CLOSED沒有任何連接狀態,
三次握手程序理解
第一次握手:建立連接時,客戶端發送syn包(syn=x)到服務器,并進入SYN_SENT狀態,等待服務器確認;SYN:同步序列編號(Synchronize Sequence Numbers),
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=x+1),同時自己也發送一個SYN包(syn=y),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=y+1),此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP連接成功)狀態,完成三次握手,
四次揮手程序理解
1)客戶端行程發出連接釋放報文,并且停止發送資料,釋放資料報文首部,FIN=1,其序列號為seq=u(等于前面已經傳送過來的資料的最后一個位元組的序號加1),此時,客戶端進入FIN-WAIT-1(終止等待1)狀態, TCP規定,FIN報文段即使不攜帶資料,也要消耗一個序號,
2)服務器收到連接釋放報文,發出確認報文,ACK=1,ack=u+1,并且帶上自己的序列號seq=v,此時,服務端就進入了CLOSE-WAIT(關閉等待)狀態,TCP服務器通知高層的應用行程,客戶端向服務器的方向就釋放了,這時候處于半關閉狀態,即客戶端已經沒有資料要發送了,但是服務器若發送資料,客戶端依然要接受,這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間,
3)客戶端收到服務器的確認請求后,此時,客戶端就進入FIN-WAIT-2(終止等待2)狀態,等待服務器發送連接釋放報文(在這之前還需要接受服務器發送的最后的資料),
4)服務器將最后的資料發送完畢后,就向客戶端發送連接釋放報文,FIN=1,ack=u+1,由于在半關閉狀態,服務器很可能又發送了一些資料,假定此時的序列號為seq=w,此時,服務器就進入了LAST-ACK(最后確認)狀態,等待客戶端的確認,
5)客戶端收到服務器的連接釋放報文后,必須發出確認,ACK=1,ack=w+1,而自己的序列號是seq=u+1,此時,客戶端就進入了TIME-WAIT(時間等待)狀態,注意此時TCP連接還沒有釋放,必須經過2∗∗MSL(最長報文段壽命)的時間后,當客戶端撤銷相應的TCB后,才進入CLOSED狀態,
6)服務器只要收到了客戶端發出的確認,立即進入CLOSED狀態,同樣,撤銷TCB后,就結束了這次的TCP連接,可以看到,服務器結束TCP連接的時間要比客戶端早一些,
參考:https://www.cnblogs.com/jessezeng/p/5617105.html
https://blog.csdn.net/qq_38950316/article/details/81087809
4.網路模型


5.http 快取機制
瀏覽器快取分為強快取和協商快取,瀏覽器加載一個頁面的簡單流程如下:
- 瀏覽器先根據這個資源的http頭資訊來判斷是否命中強快取,如果命中則直接加在快取中的資源,并不會將請求發送到服務器,
- 如果未命中強快取,則瀏覽器會將資源加載請求發送到服務器,服務器來判斷瀏覽器本地快取是否失效,若可以使用,則服務器并不會回傳資源資訊,瀏覽器繼續從快取加載資源,
- 如果未命中協商快取,則服務器會將完整的資源回傳給瀏覽器,瀏覽器加載新資源,并更新快取,

-

參考:https://www.cnblogs.com/ranyonsue/p/8918908.html
6.http狀態碼
參考http://tools.jb51.net/table/http_status_code
少見問的較多的
203:非授權資訊,請求成功,但回傳的meta資訊不在原始的服務器,而是一個副本
301:永久移動,請求的資源已被永久的移動到新URI,回傳資訊會包括新的URI,瀏覽器會自動定向到新URI,今后任何新的請求都應使用新的URI代替
302:臨時移動,與301類似,但資源只是臨時被移動,客戶端應繼續使用原有URI
304:告訴瀏覽器可以從快取中獲取所請求的資源
403:服務器拒絕此請求
405:請求的方式不對
7.介紹HTTPS
HTTP存在的安全問題:1.通信使用明文,內容可能會被竊聽,2.不驗證通信方的身份,因此有可能遭遇偽裝,3.無法證明報文的完整性,所以有可能已遭篡改,這些問題在其它未加密的協議中也會存在,HTTPS通信機制可以有效地防止這些問題,
在網路模型中添加了安全層SSL/TSL,原先是應用層將資料直接給到TCP進行傳輸,現在改成應用層將資料給到TLS/SSL,將資料加密后,再給到TCP進行傳輸,
8.介紹SSL和TLS
SSL:(Secure Socket Layer,安全套接字層),位于可靠的面向連接的網路層協議和應用層協議之間的一種協議層,SSL通過互相認證、使用數字簽名確保完整性、使用加密確保私密性,以實作客戶端和服務器之間的安全通訊,該協議由兩層組成:SSL記錄協議和SSL握手協議,
TLS:(Transport Layer Security,傳輸層安全協議),用于兩個應用程式之間提供保密性和資料完整性,該協議由兩層組成:TLS記錄協議和TLS握手協議,
參考https://kb.cnblogs.com/page/197396/
9.介紹DNS決議
瀏覽器輸入訪問地址后,會先進行本地決議hosts,如果本地沒有則開始DNS決議:
會先在LDNS進行決議,如果沒有則請求gTLD Server服務器(根),gTLD Server服務器回傳
會回傳給LDNS這個域名所屬的頂級域服務器gTLD,然后LDNS會重新向這個gTLD發送決議請求,gTLD查找到訪問地址是xx在某個服務提供商注冊的域名,它就會找到這個服務提供商的服務器Name Server,然后Name Server在它的資料庫中查找到訪問地址對應的ip并將其回傳,最終完成決議作業,
關于js的問題
1.前端通過什么做到并發請求
通過Promise.all(),web worker
關于web worker可以事先了解js運行機制j https://zhuanlan.zhihu.com/p/78113300
2. 說說JavaScript中有哪些異步編程方式?
1>回呼函式 f1(f2)
回呼函式是異步編程的基本方法,其優點是易撰寫、易理解和易部署;缺點是不利于代碼的閱讀和維護,各個部分之間高度耦合 (Coupling),流程比較混亂,而且每個任務只能指定一個回呼函式,
2>事件監聽 f1.on('done',f2)
事件監聽即采用事件驅動模式,任務的執行不取決于代碼的順序,而取決于某個事件是否發生,其優點是易理解,可以系結多個事件,每個事件可以指定多個回呼函式,可以去耦合, 有利于實作模塊化;缺點是整個程式都要變成事件驅動型,運行流程會變得不清晰,
3>發布/訂閱
f1: jQuery.publish("done");
f2: jQuery.subscribe("done", f2);
假定存在一個"信號中心",某個任務執行完成,就向信號中心"發布"(publish)一個信號,其他任務可以向信號中心"訂閱"(subscribe)這個信號,從而知道什么時候自己可以開始執行,這就叫做 "發布/訂閱模式" (publish-subscribe pattern),又稱 "觀察者模式" (observer pattern),該 方法的性質與"事件監聽"類似,但其優勢在于可以 通過查看"訊息中心",了解存在多少信號、每個信號有多少訂閱者,從而監控程式的運行,
4>promise物件 f1().then(f2)
Promises物件是CommonJS作業組提出的一種規范,目的是為異步編程提供 統一介面 ;思想是, 每一個異步任務回傳一個Promise物件,該物件有一個then方法,允許指定回呼函式,其優點是回呼函式是鏈式寫法,程式的流程非常清晰,而且有一整套的配套方法, 可以實作許多強大的功能,如指定多個回呼函式、指定發生錯誤時的回呼函式, 如果一個任務已經完成,再添加回呼函式,該回呼函式會立即執行,所以不用擔心是否錯過了某個事件或信號;缺點就是撰寫和理解相對比較難,
3.Bind、Call、Apply的區別
https://www.runoob.com/w3cnote/js-call-apply-bind.html
https://www.cnblogs.com/zhaozhenghao/p/11096000.html
4.從輸入URL到頁面加載全程序
1.讀取快取:
搜索自身的 DNS 快取,(如果 DNS 快取中找到IP 地址就跳過了接下來查找 IP 地址步驟,直接訪問該 IP 地址,)
2.DNS 決議:將域名決議成 IP 地址
3.TCP 連接:TCP 三次握手,簡易描述三次握手
客戶端:服務端你在么?
服務端:客戶端我在,你要連接我么?
客戶端:是的服務端,我要鏈接,
連接打通,可以開始請求來
4.發送 HTTP 請求
5.服務器處理請求并回傳 HTTP 報文
6.瀏覽器決議渲染頁面
7.斷開連接:TCP 四次揮手
關于第六步瀏覽器決議渲染頁面又可以聊聊如果回傳的是html頁面
根據 HTML 決議出 DOM 樹
根據 CSS 決議生成 CSS 規則樹
結合 DOM 樹和 CSS 規則樹,生成渲染樹
根據渲染樹計算每一個節點的資訊
根據計算好的資訊繪制頁面
5.介紹暫時性死區
ES6 明確規定,如果區塊中存在let和const命令,這個區塊對這些命令宣告的變數,從一開始就形成了封閉作用域,凡是在宣告之前就使用這些變數,就會報錯,
總之,在代碼塊內,使用let命令宣告變數之前,該變數都是不可用的,這在語法上,稱為“暫時性死區”
ES6 規定暫時性死區和let、const陳述句不出現變數提升,主要是為了減少運行時錯誤,防止在變數宣告前就使用這個變數,從而導致意料之外的行為,這樣的錯誤在 ES5 是很常見的,現在有了這種規定,避免此類錯誤就很容易了,
總之,暫時性死區的本質就是,只要一進入當前作用域,所要使用的變數就已經存在了,但是不可獲取,只有等到宣告變數的那一行代碼出現,才可以獲取和使用該變數,
6.ES6中的Map和原生的物件有什么區別
區別
object和Map存盤的都是鍵值對組合,但是:
object的鍵的型別是 字串;
map的鍵的型別是 可以是任意型別
另外注意,object獲取鍵值使用Object.keys(回傳陣列);
Map獲取鍵值使用 map變數.keys() (回傳迭代器),
參考https://www.cnblogs.com/mengfangui/p/9934849.html
7. 介紹一下ES6的新特性
•const和let
•模板字串
•箭頭函式
•函式的引數默認值
•Spread / Rest 運算子 https://yugasun.com/post/es6-spread-rest.html
•二進制和八進制字面量(通過在數字前面添加0o或0O即可將其轉為八進制值,二進制使用0b或者0B)
•物件和陣列解構
•ES6中的類(class)
•Promise
•Set()和Map()資料結構
•Modules(模塊, 如import, export)
•for..of 回圈
8.對閉包的看法,為什么要用閉包
閉包就是使一個函式能訪問另一個函式作用域中的變數,形成閉包之后,該變數不會被垃圾回識訓制回收,
閉包的原理其實還是作用域,
使用閉包的優點是可以避免全域變數污染,缺點是容易造成記憶體泄露,
在es5中,內部可訪問外部的變數,外部無法訪問內部的變數,想要呼叫函式內部變數時,不能直接使用,所以需要閉包的出現
參考(https://juejin.im/post/5c35d1ed518825255f0f39d8)
9.手寫陣列去重函式
// 陣列去重 es5 let arr = [0,1,8,1,6,5,7,8,1,0,10] function demo(arr){ let as= []; for(var i =0;i<arr.length;i++){ if(as.indexOf(arr[i]) === -1){ as.push(arr[i]) } } return as.sort((a,b)=>{ return a-b }); } console.log(demo(arr)) function unique(arr){ for(var i=0; i<arr.length; i++){ for(var j=i+1; j<arr.length; j++){ if(arr[i]==arr[j]){ arr.splice(j,1); j--; } } } return arr; } var arr3 = [0,9,10,15,0,5,9,10]; console.log(unique(arr3)) //es6 let arr2 = [true,"true",0,1,9,9,4,4,0] function demo2(list){ return Array.from(new Set(list)) } console.log(demo2(arr2)) function demo4(arr) { var array =[]; for(var i = 0; i < arr.length; i++) { if( !array.includes( arr[i]) ) {//includes 檢測陣列是否有某個值 array.push(arr[i]); } } return array } console.log(demo4(arr2))
10.手寫陣列扁平化函式
console.log([1, [2, [3]]].flat(Infinity))//如果不管有多少層嵌套,都要轉成一維陣列,可以用Infinity關鍵字作為引數 console.log([1, 2, [3, [4, 5]]].flat(2))//flat()的引數為2,表示要“拉平”兩層的嵌套陣列 var arr5 = [1, [2, [3, 4]]]; function flatten(arr) { return arr.reduce(function(prev, next){ console.log(prev, next) return prev.concat(Array.isArray(next) ? flatten(next) : next) }, []) } console.log(flatten(arr5))
11.合并兩個陣列
//第一種 var array = ['a', 'b']; var elements = [0, 1, 2]; array.push.apply(array, elements); console.info(array); // ["a", "b", 0, 1, 2] //第二種 var c = a.concat(b);//c=[1,2,3,4,5,6] //第三種 for(var i in b){ a.push(b[i]); }
12.記憶體泄漏
記憶體泄漏指的是應用程式中存在不需要的參考未被清除或釋放
一般指向定時器未清除干凈,以及閉包的使用,解決方法參考計數 變數為null,或者標記清除
13.原型
每一個建構式都擁有一個prototype屬性,這個屬性指向一個物件,也就是原型物件,當使用這個建構式創建實體的時候,prototype屬性指向的原型物件就成為實體的原型物件,
14.原型鏈
每個原型原型物件自身也是一個物件,它也有自己的原型物件,這樣層層上溯,就形成了一個類似鏈表的結構,這就是原型鏈
15.js中如何判斷一個值的型別
typeof運算子
console.log(typeof 123);
它對于數值、字串、布林值分別回傳number、string、boolean,函式回傳function,undefined回傳undefined,除此以外,其他情況都回傳object,
instanceof運算子
instanceof運算子回傳一個布林值,表示指定物件是否為某個建構式的實體,
instanceof運算子的左邊是實體物件,右邊是建構式,它會檢查右邊建構式的ptototype屬性,是否在左邊物件的原型鏈上,
var b = [];
b instanceof Array //true
b instanceof Object //true
注意,instanceof運算子只能用于物件,不適用原始型別的值
Object.prototype.toString方法
console.log(Object.prototype.toString.call(null)) //[object Null]
console.log(Object.prototype.toString.call(undefined)) //[object Undefined]
關于vue面試題
1.vue的生命周期
| beforeCreate | 創建前,$el,data還沒有創建 |
| created | 創建后,$el未創建,data已被初始化 |
| beforeMount | 掛在前,¥el和data,已創建,方法可呼叫,未被實體化 |
| mounted | 掛載后,資料實體化,展示在頁面 |
| beforeUpdate | 更新前,組件未被渲染 |
| updated | 更新后,陣列已渲染完成 |
| beforeDestroy | 銷毀前,實體仍然完全可用 |
| destroyed | 銷毀后,Vue 實體指示的所有東西都會解系結,所有的事件監聽器會被移除 |
2.vue資料雙向系結原理

我們已經知道實作資料的雙向系結,首先要對資料進行劫持監聽,所以我們需要設定一個監聽器Observer,用來監聽所有屬性,如果屬性發上變化了,就需要告訴訂閱者Watcher看是否需要更新,因為訂閱者是有很多個,所以我們需要有一個訊息訂閱器Dep來專門收集這些訂閱者,然后在監聽器Observer和訂閱者Watcher之間進行統一管理的,接著,我們還需要有一個指令決議器Compile,對每個節點元素進行掃描和決議,將相關指令對應初始化成一個訂閱者Watcher,并替換模板資料或者系結相應的函式,此時當訂閱者Watcher接收到相應屬性的變化,就會執行對應的更新函式,從而更新視圖,因此接下去我們執行以下3個步驟,實作資料的雙向系結:
1.實作一個監聽器Observer,用來劫持并監聽所有屬性,如果有變動的,就通知訂閱者,
2.實作一個訂閱者Watcher,可以收到屬性的變化通知并執行相應的函式,從而更新視圖,
3.實作一個決議器Compile,可以掃描和決議每個節點的相關指令,并根據初始化模板資料以及初始化相應的訂閱器,
3.說說你對 SPA 單頁面的理解,它的優缺點分別是什么?
spa初始化后,相應加載html,css,js,SPA 不會因為用戶的操作而進行頁面的重新加載或跳轉;取而代之的是利用路由機制實作 HTML 內容的變換,UI 與用戶的互動,避免頁面的重新加載,
優點:
1> 前后端分離,架構清晰
2>用戶體驗好,不需要進行重新加載頁面或者重繪,
缺點:
1>不利于seo搜索
2>對瀏覽器的前進后退不友好,建議前端寫一個自己的堆疊管理
4.怎樣理解 Vue 的單向資料流?
父子之間只有向下傳流,props,反過來不行,防止從子組件意外改變父級組件的狀態,從而導致你的應用的資料流向難以理解,
如果想要向上傳流,只能通過自定義事件$emit()
5.談談你對 keep-alive 的了解?
keep-alive是vue內置組件,主要用于快取組件
里面有倆個屬性:include,exclude,兩者都支持字串或正則運算式,其中include是名稱匹配的組件會被快取,exclude 表示任何名稱匹配的組件都不會被快取 ,其中 exclude 的優先級比 include 高;
對應兩個鉤子函式 activated 和 deactivated ,當組件被激活時,觸發鉤子函式 activated,當組件被移除時,觸發鉤子函式 deactivated,
6.組件中 data 為什么是一個函式?
因為組件是用來復用的,且 JS 里物件是參考關系,如果組件中 data 是一個物件,那么這樣作用域沒有隔離,子組件中的 data 屬性值會相互影響,如果組件中 data 選項是一個函式,那么每個實體可以維護一份被回傳物件的獨立的拷貝,組件實體之間的 data 屬性值不會互相影響;而 new Vue 的實體,是不會被復用的,因此不存在參考物件的問題,7.使用過vuex么?
Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式,每一個 Vuex 應用的核心就是 store(倉庫),“store” 基本上就是一個容器,它包含著你的應用中大部分的狀態 ( state ),
(1)Vuex 的狀態存盤是回應式的,當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那么相應的組件也會相應地得到高效更新,
(2)改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation,這樣使得我們可以方便地跟蹤每一個狀態的變化,
主要包括以下幾個模塊:
- State:定義了應用狀態的資料結構,可以在這里設定默認的初始狀態,
- Getter:允許組件從 Store 中獲取資料,mapGetters 輔助函式僅僅是將 store 中的 getter 映射到區域計算屬性,
- Mutation:是唯一更改 store 中狀態的方法,且必須是同步函式,
- Action:用于提交 mutation,而不是直接變更狀態,可以包含任意異步操作,
- Module:允許將單一的 Store 拆分為多個 store 且同時保存在單一的狀態樹中,
8.vue-router 路由模式有幾種?
vue-router 有 3 種路由模式:hash、history、abstract其中,3 種路由模式的說明如下:
-
hash: 使用 URL hash 值來作路由,支持所有瀏覽器,包括不支持 HTML5 History Api 的瀏覽器;
-
history : 依賴 HTML5 History API 和服務器配置,具體可以查看 HTML5 History 模式;
-
abstract : 支持所有 JavaScript 運行環境,如 Node.js 服務器端,如果發現沒有瀏覽器的 API,路由會自動強制進入這個模式.
9.能說下 vue-router 中常用的 hash 和 history 路由模式實作原理嗎?
(1)hash 模式的實作原理
早期的前端路由的實作就是基于 location.hash 來實作的,其實作原理很簡單,location.hash 的值就是 URL 中 # 后面的內容,
hash 路由模式的實作主要是基于下面幾個特性:
- URL 中 hash 值只是客戶端的一種狀態,也就是說當向服務器端發出請求時,hash 部分不會被發送;
- hash 值的改變,都會在瀏覽器的訪問歷史中增加一個記錄,因此我們能通過瀏覽器的回退、前進按鈕控制hash 的切換;
- 可以通過 a 標簽,并設定 href 屬性,當用戶點擊這個標簽后,URL 的 hash 值會發生改變;或者使用 JavaScript 來對 loaction.hash 進行賦值,改變 URL 的 hash 值;
- 我們可以使用 hashchange 事件來監聽 hash 值的變化,從而對頁面進行跳轉(渲染),
(2)history 模式的實作原理
HTML5 提供了 History API 來實作 URL 的變化,其中做最主要的 API 有以下兩個:history.pushState() 和 history.repalceState(),這兩個 API 可以在不進行重繪的情況下,操作瀏覽器的歷史紀錄,唯一不同的是,前者是新增一個歷史記錄,后者是直接替換當前的歷史記錄,如下所示:
window.history.pushState(null, null, path); window.history.replaceState(null, null, path);
history 路由模式的實作主要基于存在下面幾個特性:
- pushState 和 repalceState 兩個 API 來操作實作 URL 的變化 ;
- 我們可以使用 popstate 事件來監聽 url 的變化,從而對頁面進行跳轉(渲染);
- history.pushState() 或 history.replaceState() 不會觸發 popstate 事件,這時我們需要手動觸發頁面跳轉(渲染),
10.Proxy 與 Object.defineProperty 優劣對比
Proxy 的優勢如下:
- Proxy 可以直接監聽物件而非屬性;
- Proxy 可以直接監聽陣列的變化;
- Proxy 有多達 13 種攔截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具備的;
- Proxy 回傳的是一個新物件,我們可以只操作新的物件達到目的,而 Object.defineProperty 只能遍歷物件屬性直接修改;
- Proxy 作為新標準將受到瀏覽器廠商重點持續的性能優化,也就是傳說中的新標準的性能紅利;
Object.defineProperty 的優勢如下:
- 兼容性好,支持 IE9,而 Proxy 的存在瀏覽器兼容性問題,而且無法用 polyfill 磨平,因此 Vue 的作者才宣告需要等到下個大版本( 3.0 )才能用 Proxy 重寫,
11虛擬 DOM 實作原理?
虛擬 DOM 的實作原理主要包括以下 3 部分:
- 用 JavaScript 物件模擬真實 DOM 樹,對真實 DOM 進行抽象;
- diff 演算法 — 比較兩棵虛擬 DOM 樹的差異;
- pach 演算法 — 將兩個虛擬 DOM 物件的差異應用到真正的 DOM 樹,
12.vue 中的 key 有什么作用?
Vue 中 key 的作用是:key 是為 Vue 中 vnode 的唯一標記,通過這個 key,我們的 diff 操作可以更準確、更快速
更準確:因為帶 key 就不是就地復用了,在 sameNode 函式 a.key === b.key 對比中可以避免就地復用的情況,所以會更加準確,
更快速:利用 key 的唯一性生成 map 物件來獲取對應節點,比遍歷方式更快
13.你有對 Vue 專案進行哪些優化?
如果沒有對 Vue 專案沒有進行過優化總結的同學,可以參考本文作者的另一篇文章《 Vue 專案性能優化 — 實踐指南 》,文章主要介紹從 3 個大方面,22 個小方面詳細講解如何進行 Vue 專案的優化,
(1)代碼層面的優化
- v-if 和 v-show 區分使用場景
- computed 和 watch 區分使用場景
- v-for 遍歷必須為 item 添加 key,且避免同時使用 v-if
- 長串列性能優化
- 事件的銷毀
- 圖片資源懶加載
- 路由懶加載
- 第三方插件的按需引入
- 優化無限串列性能
- 服務端渲染 SSR or 預渲染
(2)Webpack 層面的優化
- Webpack 對圖片進行壓縮
- 減少 ES6 轉為 ES5 的冗余代碼
- 提取公共代碼
- 模板預編譯
- 提取組件的 CSS
- 優化 SourceMap
- 構建結果輸出分析
- Vue 專案的編譯優化
(3)基礎的 Web 技術的優化
-
開啟 gzip 壓縮
-
瀏覽器快取
-
CDN 的使用
-
使用 Chrome Performance 查找性能瓶頸
14.對于即將到來的 vue3.0 特性你有什么了解的嗎?
Vue 3.0 正走在發布的路上,Vue 3.0 的目標是讓 Vue 核心變得更小、更快、更強大,因此 Vue 3.0 增加以下這些新特性:
(1)監測機制的改變
3.0 將帶來基于代理 Proxy 的 observer 實作,提供全語言覆寫的反應性跟蹤,這消除了 Vue 2 當中基于 Object.defineProperty 的實作所存在的很多限制:
-
只能監測驗性,不能監測物件
-
檢測驗性的添加和洗掉;
-
檢測陣列索引和長度的變更;
-
支持 Map、Set、WeakMap 和 WeakSet,
新的 observer 還提供了以下特性:
- 用于創建 observable 的公開 API,這為中小規模場景提供了簡單輕量級的跨組件狀態管理解決方案,
- 默認采用惰性觀察,在 2.x 中,不管反應式資料有多大,都會在啟動時被觀察到,如果你的資料集很大,這可能會在應用啟動時帶來明顯的開銷,在 3.x 中,只觀察用于渲染應用程式最初可見部分的資料,
- 更精確的變更通知,在 2.x 中,通過 Vue.set 強制添加新屬性將導致依賴于該物件的 watcher 收到變更通知,在 3.x 中,只有依賴于特定屬性的 watcher 才會收到通知,
- 不可變的 observable:我們可以創建值的“不可變”版本(即使是嵌套屬性),除非系統在內部暫時將其“解禁”,這個機制可用于凍結 prop 傳遞或 Vuex 狀態樹以外的變化,
- 更好的除錯功能:我們可以使用新的 renderTracked 和 renderTriggered 鉤子精確地跟蹤組件在什么時候以及為什么重新渲染,
(2)模板
模板方面沒有大的變更,只改了作用域插槽,2.x 的機制導致作用域插槽變了,父組件會重新渲染,而 3.0 把作用域插槽改成了函式的方式,這樣只會影響子組件的重新渲染,提升了渲染的性能,
同時,對于 render 函式的方面,vue3.0 也會進行一系列更改來方便習慣直接使用 api 來生成 vdom ,
(3)物件式的組件宣告方式
vue2.x 中的組件是通過宣告的方式傳入一系列 option,和 TypeScript 的結合需要通過一些裝飾器的方式來做,雖然能實作功能,但是比較麻煩,3.0 修改了組件的宣告方式,改成了類式的寫法,這樣使得和 TypeScript 的結合變得很容易,
此外,vue 的原始碼也改用了 TypeScript 來寫,其實當代碼的功能復雜之后,必須有一個靜態型別系統來做一些輔助管理,現在 vue3.0 也全面改用 TypeScript 來重寫了,更是使得對外暴露的 api 更容易結合 TypeScript,靜態型別系統對于復雜代碼的維護確實很有必要,
(4)其它方面的更改
vue3.0 的改變是全面的,上面只涉及到主要的 3 個方面,還有一些其他的更改:
- 支持自定義渲染器,從而使得 weex 可以通過自定義渲染器的方式來擴展,而不是直接 fork 原始碼來改的方式,
- 支持 Fragment(多個根節點)和 Protal(在 dom 其他部分渲染組建內容)組件,針對一些特殊的場景做了處理,
- 基于 treeshaking 優化,提供了更多的內置功能,
15.導航守衛
導航守衛分為三類
全域守衛鉤子,
路由獨享守衛鉤子
組件守衛鉤子
1>全域守衛鉤子
beforeEach-----全域前置守衛
beforeResolve-----全域決議守衛
afterEach(to, from)-----全域后置守衛
2>路由獨享鉤子
beforeEnter----和beforeEach完全相同,如果都設定則在beforeEach之后緊隨執行
3>組件守衛鉤子
beforeRouterEnter-----組件實體創建之前
beforeRouterUpdate-----當前路由改變,但是該組件被復用時呼叫
beforeRouteLeave-----組件離開時呼叫
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/3842.html
標籤:其他
上一篇:《劍指Offer》各面試題總結
下一篇:python筆記09
