這是我參與8月更文挑戰的第1天,活動詳情查看:8月更文挑戰javascript
本集合是高頻面試考點,而且優化精簡了答案,便於在面試中描述。php
http: 是一個客戶端和服務器端請求和應答的標準(TCP),用於從 WWW 服務器傳輸超文本到本地瀏覽器的超文本傳輸協議。
https:是以安全爲目標的 HTTP 通道,即 HTTP 下 加入 SSL 層進行加密。css
https 協議的做用:創建一個信息安全通道,來確保數據的傳輸,確保網站的真實性。html
客戶端在使用 HTTPS 方式與 Web 服務器通訊時有如下幾個步驟:前端
創建 ssl 連接
。將網站的證書(證書中包含了公鑰),傳輸給客戶端
。協商 SSL 連接的安全等級
,也就是加密等級。創建會話密鑰
,而後經過網站的公鑰來加密會話密鑰,並傳送給網站。經過本身的私鑰解密出會話密鑰
。經過會話密鑰加密與客戶端之間的通訊
。費時
,會使頁面加載時間延長 50%,增長 10%~20%的耗電。緩存
不如 http 高效,會增長數據開銷。證書費
用越高。IP
,不能再同一個 ip 上綁定多個域名,ipv4 資源支持不了這種消耗。TCP/IP模型是互聯網的基礎,它是一系列網絡協議的總稱。這些協議能夠劃分爲四層,分別爲鏈路層、網絡層、傳輸層和應用層。vue
創建鏈接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SENT狀態,等待服務器確認
;SYN:同步序列編號(Synchronize Sequence Numbers)。服務器收到syn包並確認客戶的SYN
(ack=j+1),同時也發送一個本身的SYN包
(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1)
,此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP鏈接成功)狀態,完成三次握手。握手過程當中傳送的包裏不包含數據,三次握手完畢後,客戶端與服務器才正式開始傳送數據。
複製代碼
客戶端進程發出鏈接釋放報文
,而且中止發送數據。釋放數據報文首部,FIN=1,其序列號爲seq=u(等於前面已經傳送過來的數據的最後一個字節的序號加1),此時,客戶端進入FIN-WAIT-1(終止等待1)狀態。 TCP規定,FIN報文段即便不攜帶數據,也要消耗一個序號。2)服務器收到鏈接釋放報文,發出確認報文
,ACK=1,ack=u+1,而且帶上本身的序列號seq=v,此時,服務端就進入了CLOSE-WAIT(關閉等待)狀態。TCP服務器通知高層的應用進程,客戶端向服務器的方向就釋放了,這時候處於半關閉狀態,即客戶端已經沒有數據要發送了,可是服務器若發送數據,客戶端依然要接受。這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間。java
3)客戶端收到服務器的確認請求後,此時,客戶端就進入FIN-WAIT-2(終止等待2)狀態,等待服務器發送鏈接釋放報文(在這以前還須要接受服務器發送的最 後的數據)。node
4)服務器將最後的數據發送完畢後,就向客戶端發送鏈接釋放報文
,FIN=1,ack=u+1,因爲在半關閉狀態,服務器極可能又發送了一些數據,假定此時的序列號爲seq=w,此時,服務器就進入了LAST-ACK(最後確認)狀態,等待客戶端的確認。react
5)客戶端收到服務器的鏈接釋放報文後,必須發出確認
,ACK=1,ack=w+1,而本身的序列號是seq=u+1,此時,客戶端就進入了TIME-WAIT(時間等待)狀態。注意此時TCP鏈接尚未釋放,必須通過2∗∗MSL(最長報文段壽命)的時間後,當客戶端撤銷相應的TCB後,才進入CLOSED狀態。webpack
6)服務器只要收到了客戶端發出的確認,當即進入CLOSED狀態。一樣,撤銷TCB後,就結束了此次的TCP鏈接。能夠看到,服務器結束TCP鏈接的時間要比客戶端早一些。
TCP是面向連接
的,而UDP是面向無鏈接的。
TCP僅支持單播傳輸
,UDP 提供了單播,多播,廣播的功能。
TCP的三次握手保證了鏈接的可靠性
; UDP是無鏈接的、不可靠的一種數據傳輸協議,首先不可靠性體如今無鏈接上,通訊都不須要創建鏈接,對接收到的數據也不發送確認信號,發送端不知道數據是否會正確接收。
UDP的頭部開銷
比TCP的更小,數據傳輸速率更高
,實時性更好
。
跨域的原理
跨域,是指瀏覽器不能執行其餘網站的腳本。它是由瀏覽器的同源策略
形成的。
同源策略,是瀏覽器對 JavaScript 實施的安全限制,只要協議、域名、端口
有任何一個不一樣,都被看成是不一樣的域。
跨域原理,便是經過各類方式,避開瀏覽器的安全限制
。
解決方案
最初作項目的時候,使用的是jsonp,但存在一些問題,使用get請求不安全,攜帶數據較小,後來也用過iframe,但只有主域相同才行,也是存在些問題,後來經過了解和學習發現使用代理和proxy代理配合起來使用比較方便,就引導後臺按這種方式作下服務器配置,在開發中使用proxy,在服務器上使用nginx代理,這樣開發過程當中彼此都方便,效率也高;如今h5新特性還有 windows.postMessage()
JSONP:
ajax 請求受同源策略影響,不容許進行跨域請求,而 script 標籤 src 屬性中的鏈 接卻能夠訪問跨域的 js 腳本,利用這個特性,服務端再也不返回 JSON 格式的數據,而是 返回一段調用某個函數的 js 代碼,在 src 中進行了調用,這樣實現了跨域。
步驟:
//動態建立 script
var script = document.createElement('script');
// 設置回調函數
function getData(data) {
console.log(data);
}
//設置 script 的 src 屬性,並設置請求地址
script.src = 'http://localhost:3000/?callback=getData';
// 讓 script 生效
document.body.appendChild(script);
複製代碼
JSONP 的缺點:
JSON 只支持 get,由於 script 標籤只能使用 get 請求; JSONP 須要後端配合返回指定格式的數據。
document.domain 基礎域名相同 子域名不一樣
window.name 利用在一個瀏覽器窗口內,載入全部的域名都是共享一個window.name
CORS CORS(Cross-origin resource sharing)跨域資源共享 服務器設置對CORS的支持原理:服務器設置Access-Control-Allow-Origin HTTP響應頭以後,瀏覽器將會容許跨域請求
proxy代理 目前經常使用方式
window.postMessage() 利用h5新特性window.postMessage()
Websocket
相同點:
不一樣點:
html文件也會緩存。項目中使用index.php,後端返回html內容,不會被緩存。
瀏覽器緩存策略:
強制緩存:(在指定時間內,瀏覽器直接使用強緩存的內容)
Expires:Thu.21 Jan 2019 23:59:59 GMT; (HTTP1.0)
Cache-Control:max-age=3600(HTTP1.1,優先級更高)
【緩存指令:no-cache須要協商緩存來驗證是否過時;no-store不緩存;public客戶端代理服務器均可以緩存;private客戶端可緩存】
協商緩存:(與服務器協商,肯定資源是否更新)
Last-Modified(服務器下發時間):Thu.21 Jan 2018 23:59:59 GMT;(HTTP1.0)
If-Modified-Since(瀏覽器詢問) 【可能時間變了,內容沒變】
Etag(服務器下發); (HTTP1.1)
If-None-Match(瀏覽器詢問)
概念:
HTML5的語義化指的是合理正確的使用語義化的標籤來建立頁面結構
。【正確的標籤作正確的事】
語義化標籤:
header nav main article section aside footer
語義化的優勢:
沒CSS樣式的狀況下,頁面總體也會呈現很好的結構效果
代碼結構清晰
,易於閱讀,利於開發和維護
方便其餘設備解析(如屏幕閱讀器)根據語義渲染網頁。有利於搜索引擎優化(SEO)
,搜索引擎爬蟲會根據不一樣的標籤來賦予不一樣的權重不一樣瀏覽器的標籤默認的margin和padding不同。*{margin:0;padding:0;}
IE6雙邊距bug:塊屬性標籤float後,又有橫行的margin狀況下,在IE6顯示margin比設置的大。hack:display:inline;將其轉化爲行內屬性。
設置較小高度標籤(通常小於10px),在IE6,IE7中高度超出本身設置高度。hack:給超出高度的標籤設置overflow:hidden;或者設置行高line-height 小於你設置的高度。
Chrome 中文界面下默認會將小於 12px 的文本強制按照 12px 顯示,可經過加入 CSS 屬性 -webkit-text-size-adjust: none; 解決。
超連接訪問事後hover樣式就不出現了,被點擊訪問過的超連接樣式再也不具備hover和active了。解決方法是改變CSS屬性的排列順序:L-V-H-A ( love hate ): a:link {} a:visited {} a:hover {} a:active {}
CSS 盒模型本質上是一個盒子,它包括:邊距,邊框,填充和實際內容。CSS 中的盒子模型包括 IE 盒子模型和標準的 W3C 盒子模型。
在標準的盒子模型中,width 指 content 部分的寬度
。
在 IE 盒子模型中,width 表示 content+padding+border 這三個部分的寬度
。
故在計算盒子的寬度時存在差別:
標準盒模型: 一個塊的總寬度 = width+margin(左右)+padding(左右)+border(左右)
怪異盒模型: 一個塊的總寬度 = width+margin(左右)(既 width 已經包含了 padding 和 border 值)
BFC的概念
BFC
是 Block Formatting Context
的縮寫,即塊級格式化上下文。BFC
是CSS佈局的一個概念,是一個獨立的渲染區域,規定了內部box如何佈局, 而且這個區域的子元素不會影響到外面的元素,其中比較重要的佈局規則有內部 box 垂直放置,計算 BFC 的高度的時候,浮動元素也參與計算。
BFC的原理佈局規則
垂直方向
,一個接一個地放置垂直方向的距離由margin決定
。屬於同一個BFC的兩個相鄰Box的margin會發生重疊不會與float box重疊
子元素不會影響到外面的元素
浮動元素也參與計算高度
display屬性,決定了這個Box的類型
。不一樣類型的Box會參與不一樣的Formatting Context
。如何建立BFC?
BFC的使用場景
水平居中
對於 行內元素 : text-align: center
;
對於肯定寬度的塊級元素:
(1)width和margin實現。margin: 0 auto
;
(2)絕對定位和margin-left: -width/2, 前提是父元素position: relative
對於寬度未知的塊級元素
(1)table標籤配合margin左右auto實現水平居中
。使用table標籤(或直接將塊級元素設值爲 display:table),再經過給該標籤添加左右margin爲auto。
(2)inline-block實現水平居中方法。display:inline-block和text-align:center實現水平居中。
(3)絕對定位+transform
,translateX能夠移動自己元素的50%。
(4)flex佈局使用justify-content:center
垂直居中
line-height
實現居中,這種方法適合純文字類絕對定位
,標籤經過margin實現自適應居中table 佈局
,父級經過轉換成表格形式,而後子級設置 vertical-align 實現
。(須要注意的是:vertical-align: middle使用的前提條件是內聯元素以及display值爲table-cell的元素)。1.opacity:0
,該元素隱藏起來了,但不會改變頁面佈局,而且,若是該元素已經綁定 一些事件,如click 事件,那麼點擊該區域,也能觸發點擊事件的
2.visibility:hidden
,該元素隱藏起來了,但不會改變頁面佈局,可是不會觸發該元素已 經綁定的事件 ,隱藏對應元素,在文檔佈局中仍保留原來的空間(重繪)
3.display:none
,把元素隱藏起來,而且會改變頁面佈局,能夠理解成在頁面中把該元素。 不顯示對應的元素,在文檔佈局中再也不分配空間(迴流+重繪)
flex + px
rem + vw
包括值類型(基本對象類型)和引用類型(複雜對象類型)
基本類型(值類型): Number(數字),String(字符串),Boolean(布爾),Symbol(符號),null(空),undefined(未定義)在內存中佔據固定大小,保存在棧內存中
引用類型(複雜數據類型): Object(對象)、Function(函數)。其餘還有Array(數組)、Date(日期)、RegExp(正則表達式)、特殊的基本包裝類型(String、Number、Boolean) 以及單體內置對象(Global、Math)等 引用類型的值是對象 保存在堆內存中,棧內存存儲的是對象的變量標識符以及對象在堆內存中的存儲地址。
console.log(typeof 1); // number
console.log(typeof true); // boolean
console.log(typeof 'mc'); // string
console.log(typeof function(){}); // function
console.log(typeof console.log()); // function
console.log(typeof []); // object
console.log(typeof {}); // object
console.log(typeof null); // object
console.log(typeof undefined); // undefined
複製代碼
優勢:可以快速區分基本數據類型
缺點:不能將Object、Array和Null區分,都返回object
console.log(1 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
複製代碼
優勢:可以區分Array、Object和Function,適合用於判斷自定義的類實例對象
缺點:Number,Boolean,String基本數據類型不能判斷
var toString = Object.prototype.toString;
console.log(toString.call(1)); //[object Number]
console.log(toString.call(true)); //[object Boolean]
console.log(toString.call('mc')); //[object String]
console.log(toString.call([])); //[object Array]
console.log(toString.call({})); //[object Object]
console.log(toString.call(function(){})); //[object Function]
console.log(toString.call(undefined)); //[object Undefined]
console.log(toString.call(null)); //[object Null]
複製代碼
優勢:精準判斷數據類型
缺點:寫法繁瑣不容易記,推薦進行封裝後使用
ES6以前建立變量用的是var,以後建立變量用的是let/const
三者區別:
var定義的變量,沒有塊的概念,能夠跨塊訪問
, 不能跨函數訪問。
let定義的變量,只能在塊做用域裏訪問,不能跨塊訪問,也不能跨函數訪問。
const用來定義常量,使用時必須初始化(即必須賦值),只能在塊做用域裏訪問,且不能修改。
var能夠先使用,後聲明
,由於存在變量提高;let必須先聲明後使用。
var是容許在相同做用域內重複聲明同一個變量
的,而let與const不容許這一現象。
在全局上下文中,基於let聲明的全局變量和全局對象GO(window)沒有任何關係 ;
var聲明的變量會和GO有映射關係;
解決暫時性死區
:
暫時性死區是瀏覽器的bug:檢測一個未被聲明的變量類型時,不會報錯,會返回undefined
如:console.log(typeof a) //undefined
而:console.log(typeof a)//未聲明以前不能使用
let a
當瀏覽器開闢出供代碼執行的棧內存後,代碼並無自上而下當即執行,而是繼續作了一些事情:把當前做用域中全部帶var、function關鍵字的進行提早的聲明和定義 =>變量提高機制 【預解析】
a=3
表示給全局設置window.a=3
和在全局做用域下var a=3
是同樣的;在變量提高階段,遇到大括號
、判斷體
等,不論條件是否成立,都要進行變量提高,而在高版本瀏覽器中,函數只聲明、不賦值。
項目中,若是存在大量不被釋放的內存(堆/棧/上下文),頁面性能會變得很慢。當某些代碼操做不能被合理釋放,就會形成內存泄漏。咱們儘量減小使用閉包,由於它會消耗內存。
瀏覽器垃圾回收機制/內存回收機制:
瀏覽器的
Javascript
具備自動垃圾回收機制(GC:Garbage Collecation
),垃圾收集器會按期(週期性)找出那些不在繼續使用的變量,而後釋放其內存。
標記清除:在js
中,最經常使用的垃圾回收機制是標記清除:當變量進入執行環境時,被標記爲「進入環境」,當變量離開執行環境時,會被標記爲「離開環境」。垃圾回收器會銷燬那些帶標記的值並回收它們所佔用的內存空間。
谷歌瀏覽器:「查找引用」,瀏覽器不定時去查找當前內存的引用,若是沒有被佔用了,瀏覽器會回收它;若是被佔用,就不能回收。
IE瀏覽器:「引用計數法」,當前內存被佔用一次,計數累加1次,移除佔用就減1,減到0時,瀏覽器就回收它。
優化手段:內存優化 ; 手動釋放:取消內存的佔用便可。
(1)堆內存:fn = null 【null:空指針對象】
(2)棧內存:把上下文中,被外部佔用的堆的佔用取消便可。
內存泄漏
在 JS 中,常見的內存泄露主要有 4 種,全局變量、閉包、DOM 元素的引用、定時器
建立函數的時候,已經聲明瞭當前函數的做用域==>當前建立函數所處的上下文
。若是是在全局下建立的函數就是[[scope]]:EC(G)
,函數執行的時候,造成一個全新的私有上下文EC(FN)
,供字符串代碼執行(進棧執行)
定義:簡單來講做用域就是變量與函數的可訪問範圍,由當前環境與上層環境的一系列變量對象組成
1.全局做用域:代碼在程序的任何地方都能被訪問,window 對象的內置屬性都擁有全局做用域。
2.函數做用域:在固定的代碼片斷才能被訪問
做用:做用域最大的用處就是隔離變量
,不一樣做用域下同名變量不會有衝突。
做用域鏈參考連接通常狀況下,變量到 建立該變量 的函數的做用域中取值。可是若是在當前做用域中沒有查到,就會向上級做用域去查,直到查到全局做用域,這麼一個查找過程造成的鏈條就叫作做用域鏈。
閉包的概念
函數執行時造成的私有上下文EC(FN),正常狀況下,代碼執行完會出棧後釋放;可是特殊狀況下,若是當前私有上下文中的某個東西被上下文之外的事物佔用了,則上下文不會出棧釋放,從而造成不銷燬的上下文。 函數執行函數執行過程當中,會造成一個全新的私有上下文,可能會被釋放,可能不會被釋放,不論釋放與否,他的做用是:
(1)保護:劃分一個獨立的代碼執行區域,在這個區域中有本身私有變量存儲的空間,保護本身的私有變量不受外界干擾(操做本身的私有變量和外界沒有關係);
(2)保存:若是當前上下文不被釋放【只要上下文中的某個東西被外部佔用便可】,則存儲的這些私有變量也不會被釋放,能夠供其下級上下文中調取使用,至關於把一些值保存起來了;
咱們把函數執行造成私有上下文,來保護和保存私有變量機制稱爲閉包
。
閉包是指有權訪問另外一個函數做用域中的變量的函數--《JavaScript高級程序設計》
稍全面的回答: 在js中變量的做用域屬於函數做用域, 在函數執行完後,做用域就會被清理,內存也會隨之被回收,可是因爲閉包函數是創建在函數內部的子函數, 因爲其可訪問上級做用域,即便上級函數執行完, 做用域也不會隨之銷燬, 這時的子函數(也就是閉包),便擁有了訪問上級做用域中變量的權限,即便上級函數執行完後做用域內的值也不會被銷燬。
閉包的特性:
一、內部函數能夠訪問定義他們外部函數的參數和變量。(做用域鏈的向上查找,把外圍的做用域中的變量值存儲在內存中而不是在函數調用完畢後銷燬)設計私有的方法和變量,避免全局變量的污染。
1.1.閉包是密閉的容器,,相似於set、map容器,存儲數據的
1.2.閉包是一個對象,存放數據的格式爲 key-value 形式
二、函數嵌套函數
三、本質是將函數內部和外部鏈接起來。優勢是能夠讀取函數內部的變量,讓這些變量的值始終保存在內存中,不會在函數被調用以後自動清除
閉包造成的條件:
閉包的用途:
閉包應用場景
閉包的兩個場景,閉包的兩大做用:保存/保護
。 在開發中, 其實咱們隨處可見閉包的身影, 大部分前端JavaScript 代碼都是「事件驅動」的,即一個事件綁定的回調方法; 發送ajax請求成功|失敗的回調;setTimeout的延時回調;或者一個函數內部返回另外一個匿名函數,這些都是閉包的應用。
閉包的優勢:延長局部變量的生命週期
閉包缺點:會致使函數的變量一直保存在內存中,過多的閉包可能會致使內存泄漏
this
指向window
。this
就會指向該對象
。this
指向返回的這個對象
。this
綁定看的是this所在函數定義在哪一個對象下
,就綁定哪一個對象。若是有嵌套的狀況,則this綁定到最近的一層對象上。apply 、 call 和 bind
調用模式,這三個方法均可以顯示的指定調用函數的 this 指向。apply
接收參數的是數組,call
接受參數列表,`` bind方法經過傳入一個對象,返回一個
this 綁定了傳入對象的新函數。這個函數的
this指向除了使用
new `時會被改變,其餘狀況下都不會改變。若爲空默認是指向全局對象window。原型關係:
原型: 在 JS 中,每當定義一個對象(函數也是對象)時,對象中都會包含一些預約義的屬性。其中每一個函數對象
都有一個prototype
屬性,這個屬性指向函數的原型對象
。
原型鏈:函數的原型鏈對象constructor默認指向函數自己,原型對象除了有原型屬性外,爲了實現繼承,還有一個原型鏈指針__proto__,該指針是指向上一層的原型對象,而上一層的原型對象的結構依然相似。所以能夠利用__proto__一直指向Object的原型對象上,而Object原型對象用Object.prototype.__ proto__ = null表示原型鏈頂端。如此造成了js的原型鏈繼承。同時全部的js對象都有Object的基本防範
特色: JavaScript
對象是經過引用來傳遞的,咱們建立的每一個新對象實體中並無一份屬於本身的原型副本。當咱們修改原型時,與之相關的對象也會繼承這一改變。
空對象
設置原型
,將對象的原型設置爲函數的prototype
對象。this
指向這個對象,執行構造函數的代碼(爲這個新對象添加屬性)JS
是單線程的,爲了防止一個函數執行時間過長阻塞後面的代碼,因此會先將同步代碼壓入執行棧中,依次執行,將異步代碼推入異步隊列,異步隊列又分爲宏任務隊列和微任務隊列,由於宏任務隊列的執行時間較長,因此微任務隊列要優先於宏任務隊列。微任務隊列的表明就是,Promise.then
,MutationObserver
,宏任務的話就是setImmediate setTimeout setInterval
JS運行的環境。通常爲瀏覽器或者Node。 在瀏覽器環境中,有JS 引擎線程和渲染線程,且兩個線程互斥。 Node環境中,只有JS 線程。 不一樣環境執行機制有差別,不一樣任務進入不一樣Event Queue隊列。 當主程結束,先執行準備好微任務,而後再執行準備好的宏任務,一個輪詢結束。
事件環的運行機制是,先會執行棧中的內容,棧中的內容執行後執行微任務,微任務清空後再執行宏任務,先取出一個宏任務,再去執行微任務,而後在取宏任務清微任務這樣不停的循環。
eventLoop 是由JS的宿主環境(瀏覽器)來實現的;
事件循環能夠簡單的描述爲如下四個步驟:
瀏覽器中的任務源(task):
宏任務(macrotask)
:
宿主環境提供的,好比瀏覽器
ajax、setTimeout、setInterval、setTmmediate(只兼容ie)、script、requestAnimationFrame、messageChannel、UI渲染、一些瀏覽器api
微任務(microtask)
:
語言自己提供的,好比promise.then
then、queueMicrotask(基於then)、mutationObserver(瀏覽器提供)、messageChannel 、mutationObersve
Node
是基於V8引擎的運行在服務端的JavaScript
運行環境,在處理高併發、I/O密集(文件操做、網絡操做、數據庫操做等)場景有明顯的優點。雖然用到也是V8引擎,但因爲服務目的和環境不一樣,致使了它的API與原生JS有些區別,其Event Loop還要處理一些I/O,好比新的網絡鏈接等,因此Node的Event Loop(事件環機制)與瀏覽器的是不太同樣。
執行順序以下:
timers
: 計時器,執行setTimeout和setInterval的回調pending callbacks
: 執行延遲到下一個循環迭代的 I/O 回調idle, prepare
: 隊列的移動,僅系統內部使用poll輪詢
: 檢索新的 I/O 事件;執行與 I/O 相關的回調。事實上除了其餘幾個階段處理的事情,其餘幾乎全部的異步都在這個階段處理。check
: 執行setImmediate
回調,setImmediate在這裏執行close callbacks
: 執行close
事件的callback
,一些關閉的回調函數,如:socket.on('close', ...)setTimeout
settimeout的回調函數放到宏任務隊列裏,等到執行棧清空之後執行。
Promise
Promise自己是同步的當即執行函數, 當在executor中執行resolve或者reject的時候, 此時是異步操做, 會先執行then/catch等,當主棧完成後,纔會去調用resolve/reject中存放的方法執行。
console.log('script start')
let promise1 = new Promise(function (resolve) {
console.log('promise1')
resolve()
console.log('promise1 end')
}).then(function () {
console.log('promise2')
})
setTimeout(function(){
console.log('settimeout')
})
console.log('script end')
// 輸出順序: script start->promise1->promise1 end->script end->promise2->settimeout
複製代碼
async/await
async 函數返回一個 Promise 對象,當函數執行的時候,一旦遇到 await 就會先返回,等到觸發的異步操做完成,再執行函數體內後面的語句。能夠理解爲,是讓出了線程,跳出了 async 函數體。
async function async1(){
console.log('async1 start');
await async2();
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start');
async1();
console.log('script end')
// 輸出順序:script start->async1 start->async2->script end->async1 end
複製代碼
Async/Await就是一個自執行的generate函數。利用generate函數的特性把異步的代碼寫成「同步」的形式,第一個請求的返回值做爲後面一個請求的參數,其中每個參數都是一個promise對象.
概念:set是ES6新增的數據結構。集合
的概念是一組無序且惟一
(即不重複)的項組成。set數據結構使用了與有限集合相同的數學概念,應用在計算機的數據結構中,與數組相似,但成員都是惟一的,沒有重複的值。
特色:key和value相同,沒有重複的value。只有健值,沒有健名,有點相似數組。
屬性:set.size set大小
set經常使用的方法
一、set.add(value)添加一個數據,返回Set結構自己 二、set.delete(value)刪除指定數據,表示刪除是否成功 三、set.has(value)判斷該值是否爲set成員,返回一個布爾值 四、set.clear() 清除全部數據,沒有返回值 五、set.keys()返回鍵名的遍歷器 六、set.values()返回鍵值的遍歷器 七、entries()返回鍵值對的遍歷器 八、forEach()使用回調函數的每一個成員
WeakSet 對象容許你將弱引用對象
儲存在一個集合中
WeakSet 與 Set 的區別:
屬性:
Map 是一種叫作字典
的數據結構,Map和對象最大的不一樣應該就是鍵能夠是任意類型
Map結構的實例有如下屬性:
1.size屬性 size
屬性返回Map結構的成員總數。 2.set(key, value) 3.get(key) get
方法讀取key
對應的鍵值,若是找不到key
,返回undefined
。 4.has(key) has
方法返回一個布爾值,表示某個鍵是否在Map數據結構中。 5.delete(key) delete
方法刪除某個鍵,返回true。若是刪除失敗,返回false。 6.clear() clear
方法清除全部成員,沒有返回值。
Map原生提供三個遍歷器生成函數和一個遍歷方法。
keys()
:返回鍵名的遍歷器。values()
:返回鍵值的遍歷器。entries()
:返回全部成員的遍歷器。forEach()
:遍歷Map的全部成員。須要特別注意的是,Map的遍歷順序就是插入順序。
WeakMap 對象是一組鍵值對的集合,其中的鍵是弱引用對象,而值能夠是任意。
注意,WeakMap 弱引用的只是鍵名,而不是鍵值。鍵值依然是正常引用。
WeakMap 中,每一個鍵對本身所引用對象的引用都是弱引用,在沒有其餘引用和該鍵引用同一對象,這個對象將會被垃圾回收(相應的key則變成無效的),因此,WeakMap 的 key 是不可枚舉的。
屬性:
方法:
weakSet
什麼是MVVM?
視圖模型雙向綁定
,是Model-View-ViewModel
的縮寫,也就是把MVC
中的Controller
演變成ViewModel。Model
層表明數據模型,View
表明UI組件,ViewModel
是View
和Model
層的橋樑,數據會綁定到viewModel
層並自動將數據渲染到頁面中,視圖變化的時候會通知viewModel
層更新數據。之前是操做DOM結構更新視圖,如今是數據驅動視圖
。
MVVM的優勢:
1.低耦合
。視圖(View)能夠獨立於Model變化和修改,一個Model能夠綁定到不一樣的View上,當View變化的時候Model能夠不變化,當Model變化的時候View也能夠不變;
2.可重用性
。你能夠把一些視圖邏輯放在一個Model裏面,讓不少View重用這段視圖邏輯。
3.獨立開發
。開發人員能夠專一於業務邏輯和數據的開發(ViewModel),設計人員能夠專一於頁面設計。
4.可測試
。
Vue做爲MVVM模式的實現庫的2種技術
a. 模板解析
b. 數據綁定
模板解析:實現初始化顯示
a. 解析大括號表達式
b. 解析指令
數據綁定:實現更新顯示
a. 經過數據劫持實現
建立了兩種對象Observer和complie,先建立的Observer,後建立的complie,observer是爲了監視/劫持data中全部層次的屬性,同時還爲每一種屬性建立了另一種對象dep,dep與data中的屬性一一對應,complie做用是用來編譯模版,初始化界面,調用update對象,complie還爲每一個表達式建立了對應的watcher同時指定了更新節點的回調函數,將watcher添加到全部對應的dep中,
什麼是虛擬dom
說白了就是以js對象的形式去添加dom元素
本質上是優化了diff算法
虛擬dom自己也有本身的缺陷他更適合批量修改dom
儘可能不要跨層級修改dom
設置key能夠最大的利用節點,避免重複渲染
1、什麼是vdom?
Virtual DOM 用JS模擬DOM結構用。JavaScript 對象結構表示 DOM 樹的結構;而後用這個樹構建一個真正的 DOM 樹, 插到文檔當中 當狀態變動的時候,從新構造一棵新的對象樹。而後用新的樹和舊的樹 進行比較,記錄兩棵樹差別 把所記錄的差別應用到所構建的真正的 DOM 樹上,視圖就 更新了。Virtual DOM 本質上就是在 JS 和 DOM 之間作了一個緩存。
創建一個與 dom 樹對應的虛擬 dom 對象( js 對象),以對象嵌套的方式來表示 dom 樹,那麼每次 dom 的更改就變成了 js 對象的屬性的更改,這樣一來就能查找 js 對象 的屬性變化要比查詢 dom 樹的性能開銷小。
2、爲什麼要用vdom?
DOM操做很是很是「rang貴」,將DOM對比操做放在JS層,提升效率
DOM結構的對比,放在JS層來作(圖靈完備語言:能實現邏輯代碼的語言)
3、vdom核心函數有哪些
核心函數:
h('標籤名', {...屬性名...}, [...子元素...])
h('標籤名', {...屬性名...}, '.........')
patch(container, vnode)
patch(vnode, newVnode)
vue.js是採用數據劫持結合發佈者-訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter和getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調
Vue是一個典型的MVVM框架,模型(Model)只是普通的javascript對象,修改它則試圖(View)會自動更新。這種設計讓狀態管理變得很是簡單而直觀
Observer(數據監聽器): Observer的核心是經過Object.defineProprtty()來監聽數據的變更,這個函數內部能夠定義setter和getter,每當數據發生變化,就會觸發setter。這時候Observer就要通知訂閱者,訂閱者就是Watcher
Watcher(訂閱者): Watcher訂閱者做爲Observer和Compile之間通訊的橋樑,主要作的事情是:
Compile(指令解析器): Compile主要作的事情是解析模板指令,將模板中變量替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加鑑定數據的訂閱者,一旦數據有變更,收到通知,更新試圖
level1: vue2.0中,響應式實現的核心就是 ES5的Object.defineProperty(obj, prop, descriptor). 經過Object.defineProperty()劫持data和props各個屬性的getter和setter,getter作依賴收集,setter派發更新。總體來講是一個 數據劫持 + 發佈-訂閱者模式。
level2: 具體來講, ① vue初始化階段(beforeCreate以後create以前),遍歷data/props,調用Object.defineProperty給每一個屬性加上getter、setter。② 每一個組件、每一個computed都會實例化一個watcher(固然也包括每一個自定義watcher),訂閱渲染/計算所用到的所用data/props/computed,一旦數據發生變化,setter被調用,會通知渲染watcher從新計算、更新組件。
問題4 vue組件通訊 level1: props+events 父子組件通訊(parent/parent/parent/children),vuex 任何組件通訊,事件中心emit/emit / emit/on 任何組件的通訊, attrs/attrs/attrs/listeners 後代通訊(provide / inject)。
level2: vuex運行機制:vuex的state做爲一個倉庫,提供數據驅動vue component渲染。視圖經過dispach派發actions,actions中能夠作一些異步操做。actions或者視圖經過commit提交給mutations,mutation去改變state。
level3: 源碼分析:vuex實際上是一個Vue.js插件,插件都須要提供一個install方法,install方法調用會將Vue做爲參數傳入。Vue.user(plugin)安裝插件,也就是執行插件的install方法。會在全局混入一個beforeCreate鉤子函數,把示例化的Store保存到全部組件的this.$store中。
level4: mutation改變state, 會觸發視圖改變的緣由?經過vue實現的,[實例化vue,把state做爲一個data屬性。] ↔️ 核心
參考回答: 一則語法糖,至關於 v-bind:value="xxx" 和 @input,意思是綁定了一個 value 屬性的值, 子組件可對 value 屬性監聽,經過$emit('input', xxx)的方式給父組件通信。本身實現 v-model 方式的組件也是這樣的思路。
每一個Vue
實例在建立時都會通過一系列的初始化過程,vue
的生命週期鉤子,就是說在達到某一階段或條件時去觸發的函數,目的就是爲了完成一些動做或者事件
create階段
:vue實例被建立beforeCreate
: 建立前,此時data和methods中的數據都尚未初始化created
: 建立完畢,data中有值,未掛載mount階段
: vue實例被掛載到真實DOM節點beforeMount
:能夠發起服務端請求,去數據mounted
: 此時能夠操做DOMupdate階段
:當vue實例裏面的data數據變化時,觸發組件的從新渲染 beforeUpdate
:更新前updated
:更新後destroy階段
:vue實例被銷燬 beforeDestroy
:實例被銷燬前,此時能夠手動銷燬一些方法 destroyed
:銷燬後生命週期(父子組件) 父組件beforeCreate --> 父組件created --> 父組件beforeMount --> 子組件beforeCreate --> 子組件created --> 子組件beforeMount --> 子組件 mounted --> 父組件mounted -->父組件beforeUpdate -->子組件beforeDestroy--> 子組件destroyed --> 父組件updated
加載渲染過程 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
掛載階段 父created->子created->子mounted->父mounted
父組件更新階段 父beforeUpdate->父updated
子組件更新階段 父beforeUpdate->子beforeUpdate->子updated->父updated
銷燬階段 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
computed與watch
通俗來說,既能用 computed 實現又能夠用 watch 監聽來實現的功能,推薦用 computed, 重點在於 computed 的緩存功能 computed 計算屬性是用來聲明式的描述一個值依賴了其它的值,當所依賴的值或者變量 改變時,計算屬性也會跟着改變; watch 監聽的是已經在 data 中定義的變量,當該變量變化時,會觸發 watch 中的方法。
watch 屬性監聽 是一個對象,鍵是須要觀察的屬性,值是對應回調函數,主要用來監聽某些特定數據的變化,從而進行某些具體的業務邏輯操做,監聽屬性的變化,須要在數據變化時執行異步或開銷較大的操做時使用
computed 計算屬性 屬性的結果會被緩存
,當computed
中的函數所依賴的屬性沒有發生改變的時候,那麼調用當前函數的時候結果會從緩存中讀取。除非依賴的響應式屬性變化時纔會從新計算,主要當作屬性來使用 computed
中的函數必須用return
返回最終的結果 computed
更高效,優先使用。data 不改變,computed 不更新。
使用場景 computed
:當一個屬性受多個屬性影響的時候使用,例:購物車商品結算功能 watch
:當一條數據影響多條數據的時候使用,例:搜索數據
1.一個組件被複用屢次的話,也就會建立多個實例。本質上,這些實例用的都是同一個構造函數。 2.若是data是對象的話,對象屬於引用類型,會影響到全部的實例。因此爲了保證組件不一樣的實例之間data不衝突,data必須是一個函數。
1.當 v-for 和 v-if 處於同一個節點時,v-for 的優先級比 v-if 更高,這意味着 v-if 將分別重複運行於每一個 v-for 循環中。若是要遍歷的數組很大,而真正要展現的數據不多時,這將形成很大的性能浪費 2.這種場景建議使用 computed,先對數據進行過濾
key的做用是爲了在diff算法執行時更快的找到對應的節點,提升diff速度,更高效的更新虛擬DOM
;
vue和react都是採用diff算法來對比新舊虛擬節點,從而更新節點。在vue的diff函數中,會根據新節點的key去對比舊節點數組中的key,從而找到相應舊節點。若是沒找到就認爲是一個新增節點。而若是沒有key,那麼就會採用遍歷查找的方式去找到對應的舊節點。一種一個map映射,另外一種是遍歷查找。相比而言。map映射的速度更快。
爲了在數據變化時強制更新組件,以免「就地複用」
帶來的反作用。
當 Vue.js 用 v-for
更新已渲染過的元素列表時,它默認用「就地複用」策略。若是數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序,而是簡單複用此處每一個元素,而且確保它在特定索引下顯示已被渲染過的每一個元素。重複的key會形成渲染錯誤。
props
/$emit
父子組件通訊
父->子props
,子->父 $on、$emit
獲取父子組件實例 parent、children
Ref
獲取實例的方式調用組件的屬性或者方法 父->子孫 Provide、inject
官方不推薦使用,可是寫組件庫時很經常使用
$emit
/$on
自定義事件 兄弟組件通訊
Event Bus
實現跨組件通訊 Vue.prototype.$bus = new Vue()
自定義事件
vuex 跨級組件通訊
Vuex、$attrs、$listeners
Provide、inject
當一個Vue實例建立時,Vue會遍歷data選項的屬性,用 Object.defineProperty 將它們轉爲 getter/setter而且在內部追蹤相關依賴,在屬性被訪問和修改時通知變化。每一個組件實例都有相應的 watcher 程序實例,它會在組件渲染的過程當中把屬性記錄爲依賴,以後當依賴項的 setter 被調用時,會通知 watcher從新計算,從而導致它關聯的組件得以更新。
vue
中雙向綁定是一個指令v-model
,能夠綁定一個動態值到視圖,同時視圖中變化能改變該值。v-model
是語法糖,默認狀況下相於:value和@input
。v-model
能夠減小大量繁瑣的事件處理代碼,提升開發效率,代碼可讀性也更好v-model
v-model
,自定義組件上若是要使用它須要在組件內綁定value並處理輸入事件v-model
模板的組件渲染函數,發現它會被轉換爲value屬性的綁定以及一個事件監聽,事件回調函數中會作相應變量更新操做,這說明神奇魔法其實是vue的編譯器完成的。nextTick
是Vue
提供的一個全局API
,是在下次DOM
更新循環結束以後執行延遲迴調,在修改數據以後使用$nextTick
,則能夠在回調中獲取更新後的DOM
;Vue
將開啓1個隊列,並緩衝在同一事件循環中發生的全部數據變動。若是同一個watcher
被屢次觸發,只會被推入到隊列中-次。這種在緩衝時去除重複數據對於避免沒必要要的計算和DOM
操做是很是重要的。nextTick
方法會在隊列中加入一個回調函數,確保該函數在前面的dom操做完成後才調用;nextTick
實現,它會在callbacks
裏面加入咱們傳入的函數,而後用timerFunc
異步方式調用它們,首選的異步方式會是Promise
。這讓我明白了爲何能夠在nextTick
中看到dom
操做結果。在下次 DOM 更新循環結束以後執行延遲迴調,在修改數據以後當即使用 nextTick 來獲取更新後的 DOM。 nextTick主要使用了宏任務和微任務。 根據執行環境分別嘗試採用Promise、MutationObserver、setImmediate,若是以上都不行則採用setTimeout定義了一個異步方法,屢次調用nextTick會將方法存入隊列中,經過這個異步方法清空當前隊列。
vue中的插槽是一個很是好用的東西slot說白了就是一個佔位的 在vue當中插槽包含三種一種是默認插槽(匿名)一種是具名插槽還有一種就是做用域插槽 匿名插槽就是沒有名字的只要默認的都填到這裏具名插槽指的是具備名字的
做用:實現組件緩存,保持這些組件的狀態,以免反覆渲染致使的性能問題。 須要緩存組件 頻繁切換,不須要重複渲染
場景:tabs標籤頁 後臺導航,vue性能優化
原理:Vue.js
內部將DOM
節點抽象成了一個個的VNode
節點,keep-alive
組件的緩存也是基於VNode
節點的而不是直接存儲DOM
結構。它將知足條件(pruneCache與pruneCache)
的組件在cache
對象中緩存起來,在須要從新渲染的時候再將vnode
節點從cache
對象中取出並渲染。
mixin 項目變得複雜的時候,多個組件間有重複的邏輯就會用到mixin
多個組件有相同的邏輯,抽離出來
mixin並非完美的解決方案,會有一些問題
vue3提出的Composition API旨在解決這些問題【追求完美是要消耗必定的成本的,如開發成本】
場景:PC端新聞列表和詳情頁同樣的右側欄目,能夠使用mixin進行混合
劣勢:1.變量來源不明確,不利於閱讀 2.多mixin可能會形成命名衝突 3.mixin和組件可能出現多對多的關係,使得項目複雜度變高
複製代碼
狀態管理庫,相似 React 中的 Rudux
關於vuex vuex是一個專門爲vue構建的狀態集管理,主要是爲了解決組件間狀態共享的問題,強調的是數據的集中式管理,說白了主要是便於維護便於解耦因此不是全部的項目都適合使用vuex,若是你不是構建大型項目使用vuex反而使你的項目代碼繁瑣多餘
vuex的核心: state mutations getters actions modules
Vuex 是一個專爲 Vue 應用程序開發的狀態管理模式。每個 Vuex 應用的核心就是 store(倉庫)。
若 store 中的狀態發生變化,那麼相應的組件也會相應地獲得高效更新 2. 改變 store 中的狀態的惟一途徑就是顯式地提交 (commit) mutation, 這樣使得咱們能夠方便地跟蹤每個狀態的變化 Vuex主要包括如下幾個核心模塊:
就像計算屬性同樣,getter 的返回值會根據它的依賴被緩存起來, 且只有當它的依賴值發生了改變纔會被從新計算 3. Mutation:是惟一更改 store 中狀態的方法,且必須是同步函數 4. Action:用於提交 mutation,而不是直接變動狀態,能夠包含任意異步操做 5. Module:容許將單一的 Store 拆分爲多個 store 且同時保存在單一的狀態樹中
1)對Vuex基本理解1)是什麼:Vuex是一個專爲Vue.js應用程序開發的狀態管理的vue插件2)做用:集中式管理vue多個組件共享的狀態和從後臺獲取的數據states幫助組件管理狀態的,基於state的還有一個計算屬性數據getters,getters是從state中讀取數據並計算的,他們兩個的數據都是給組件去讀,組件中讀取state狀態數據使用 store.getters和mapGetters();更新狀態數據涉及到actions和mutations,經過$store.dispatch或mapAction()觸發action的調用,而後actions會經過commit()觸發mutations調用,mutations則直接更新狀態;actions還能夠同後臺API進行雙向通訊。
「單向數據流」理念的極簡示意:
簡單的單向數據流(unidirectional data flow)是指用戶訪問View,View發出用戶交互的Action,在Action裏對state進行相應更新。state更新後會觸發View更新頁面的過程。這樣數據老是清晰的單向進行流動,便於維護而且能夠預測
問題:渲染真實的DOM開銷是很大的,修改了某個數據,若是直接渲染到真實dom上會引發整個DOM樹的重繪和重排。 Virtual Dom 根據真實DOM生成的一個Virtual DOM,當Virtual DOM某個節點的數據改變後生成一個新的Vnode,而後Vnode和oldVnode做對比,發現有不同的地方就直接修改在真實的DOM上,而後使oldVnode的值爲Vnode. 注意:在採起diff算法比較的時候,只會在同層級進行,不會跨層級比較。 當數據發生改變時,set方法會讓調用Dep.notify()方法通知全部訂閱者Watcher,訂閱者就會調用patch函數給真實的DOM打補丁,更新響應的試圖。
更小巧、更快速 支持自定義渲染器 支持搖樹優化:一種在打包時去除無用代碼的優化手段 支持Fragments和跨組件渲染
模板語法99%保持不變 原生支持基於class的組件,而且無需藉助任何編譯及各類stage階段的特性 在設計時也考慮TypeScript的類型推斷特性 重寫虛擬DOM
能夠期待更多的編譯時提示來減小運行時的開銷 優化插槽生成
能夠單獨渲染父組件和子組件 靜態樹提高
下降渲染成本 基於Proxy的觀察者機制
節省內存開銷
檢測機制
更加全面、精準、高效,更具可調試式的響應跟蹤
a. 生成 Block tree Vue.js 2.x 的數據更新並觸發從新渲染的粒度是組件級的,單個組件內部 須要遍歷該組 件的整個 vnode 樹。在 2.0 裏,渲染效率的快慢與組件大小成正相關:組件越大,渲染 效率越慢。而且,對於一些靜態節點,又無數據更新,這些遍歷都是性能浪費。 Vue.js 3.0 作到了經過編譯階段對靜態模板的分析,編譯生成了 Block tree。 Block tree 是一個將模版基於動態節點指令切割的嵌套區塊,每一個 區塊內部的節點結構是固定的, 每一個區塊只須要追蹤自身包含的動態節點。因此,在 3.0 裏,渲染效率再也不與模板大小 成正相關,而是與模板中動態節點的數量成正相關。
b. slot 編譯優化 Vue.js 2.x 中,若是有一個組件傳入了 slot,那麼每次父組件更新的時候,會強制使子組 件 update,形成性能的浪費。 Vue.js 3.0 優化了 slot 的生成,使得非動態 slot 中屬性的更新只會觸發子組件的更新。 動態 slot 指的是在 slot 上面使用 v-if,v-for,動態 slot 名字等會致使 slot 產生運行時動 態變化可是又沒法被子組件 track 的操做。 c. diff 算法優化
a. diff 方法優化 Vue2.x 中的虛擬 dom 是進行全量的對比。 Vue3.0 中新增了靜態標記(PatchFlag):在與上次虛擬結點進行對比的時候,值對比 帶有 patch flag 的節點,而且能夠經過 flag 的信息得知當前節點要對比的具體內容化。 b. hoistStatic 靜態提高 Vue2.x : 不管元素是否參與更新,每次都會從新建立。 Vue3.0 : 對不參與更新的元素,只會被建立一次,以後會在每次渲染時候被不停的複用。 c. cacheHandlers 事件偵聽器緩存 默認狀況下 onClick 會被視爲動態綁定,因此每次都會去追蹤它的變化可是由於是同一 個函數,因此沒有追蹤變化,直接緩存起來複用便可。 原做者姓名: 歐陽呀
2.0存在的問題 1.對原始數據進行克隆一份 2.須要分別給對象中的每一個屬性設置監聽 3.0裏面使用的是proxy監聽對象中的全部的屬性
Composition API 與 React.js 中 Hooks 的異同點
a. React.js 中的 Hooks 基本使用 React Hooks 容許你 "勾入" 諸如組件狀態和反作用處理等 React 功能中。Hooks 只能 用在函數組件中,並容許咱們在不須要建立類的狀況下將狀態、反作用處理和更多東西 帶入組件中。 React 核心團隊奉上的採納策略是不反對類組件,因此你能夠升級 React 版本、在新組 件中開始嘗試 Hooks,並保持既有組件不作任何更改。 案例: useState 和 useEffect 是 React Hooks 中的一些例子,使得函數組件中也能增長狀態和 運行反作用。 咱們也能夠自定義一個 Hooks,它打開了代碼複用性和擴展性的新大門。
編碼階段
儘可能減小data中的數據及層次結構,data中的數據都會增長getter和setter,會收集對應的watcher v-if和v-for不能連用 若是須要使用v-for給每項元素綁定事件時使用事件代理 SPA 頁面採用keep-alive緩存組件 在更多的狀況下,使用v-if替代v-show key保證惟一 使用路由懶加載、異步組件 防抖、節流 第三方模塊按需導入 長列表滾動到可視區域動態加載 圖片懶加載
SEO優化
預渲染 服務端渲染SSR 打包優化 壓縮代碼 Tree Shaking/Scope Hoisting 使用cdn加載第三方模塊 多線程打包happypack splitChunks抽離公共文件 sourceMap優化
用戶體驗
骨架屏 PWA 還能夠使用緩存(客戶端緩存、服務端緩存)優化、服務端開啓gzip壓縮等。
相同點: 1.都是組件化開發和虛擬DOM(Virtual Dom) 2.都支持經過props進行父子組件間數據通訊 3.都支持數據驅動視圖,不直接操做DOM,更新狀態數據界面就自動更新 4.都支持服務端渲染 5.都支持native的方案,React的 React Native, Vue 的Weex
不一樣點: 1.數據綁定:vue實現了數據的雙向綁定,react的數據流動是單向的 2.組件的寫法不同,React推薦的是JSX語法,也就是把HTML和CSS都寫進JavaScript,即"all in js";vue推薦的作法是webpack+vue+loader的單文件組件格式,即html,css,js寫在同一個文件中; 3.數據狀態管理不一樣,state對象在react應用中是不可變的,須要使用setState方法更新狀態;在vue中state對象不是必須的,數據由data屬性在vue對象中管理 4.Virtual Dom不同,vue會跟蹤每一個組件的依賴關係,不須要從新渲染整個組件樹; 而對於react而言,每當應用的狀態改變時,所有的組件都會被渲染,因此react中會須要shouldComponentUpdate這個生命週期函數方法來進行控制 5.React嚴格上只針對MVC的View層,Vue則是MVVM模式
使用公共組件進行狀態提高
react中父子組件中參數互傳,子傳父是先在父組件上綁定屬性設置爲一個函數,當子組件須要給父組件傳值的時候,則經過props調用該函數將參數傳入到該函數當中,此時就能夠在父組件中的函數中接收到該參數了,這個參數則爲子組件傳過來的值
父傳子是在父組件中直接綁定一個正常的屬性,這個屬性就是指具體的值,在子組件中,用props就能夠獲取到這個值
1.能夠new一個 Vue 的 EventBus,進行事件監聽,一邊執行監聽,一邊執行新增 VUE的eventBus 就是發佈訂閱模式,是能夠在React中使用的;
2.使用pubsub-js
3.redux
1.異步狀況 在React事件當中是異步操做
2.同步狀況 若是是在setTimeout事件或者自定義的dom事件中,都是同步的
3.同步狀況 自定義dom事件 屢次的異步setState,更新前會進行合併 屢次的異步setState,更新前不進行合併
安裝
當組件的實例被建立並插入到 DOM 中時,這些方法按如下順序調用:
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()
更新中
更新可能由道具或狀態的更改引發。當從新渲染組件時,這些方法按如下順序調用:
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
卸載
當組件從 DOM 中移除時調用此方法:
componentWillUnmount()
複製代碼
Portals 提供了一種一流的方式來將子組件渲染到存在於父組件的 DOM 層次結構以外的 DOM 節點中。結構不受外界的控制的狀況下就能夠使用portals進行建立
// 異步懶加載
const Box = lazy(()=>import('./components/Box'));
// 使用組件的時候要用suspense進行包裹
<Suspense fallback={<div>loading...</div>}> {show && <Box/>} </Suspense>
複製代碼
immutable內部提供的全部數據類型,對其數據進行任意操做,操做獲得的結果是修改後的值 而且修改後的值是一個新的對象,原來的對象沒有發生任何變化。
1. 概念
節流:事件觸發後,規定時間內,事件處理函數不能再次被調用。也就是說在規定的時間內,函數只能被調用一次,且是最早被觸發調用的那次。
function debounce(fn) {
let timeout = null; // 建立一個標記用來存放定時器的返回值
return function () {
clearTimeout(timeout); // 每當用戶輸入的時候把前一個 setTimeout clear 掉
timeout = setTimeout(() => { // 而後又建立一個新的 setTimeout, 這樣就能保證輸入字符後的 interval 間隔內若是還有字符輸入的話,就不會執行 fn 函數
fn.apply(this, arguments);
}, 500);
};
}
function sayHi() {
console.log('防抖成功');
}
var inp = document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi)); // 防抖
複製代碼
防抖:屢次觸發事件,事件處理函數只能執行一次,而且是在觸發操做結束時執行。
function throttle(fn) {
let canRun = true; // 經過閉包保存一個標記
return function () {
if (!canRun) return; // 在函數開頭判斷標記是否爲true,不爲true則return
canRun = false; // 當即設置爲false
setTimeout(() => { // 將外部傳入的函數的執行放在setTimeout中
fn.apply(this, arguments);
// 最後在setTimeout執行完畢後再把標記設置爲true(關鍵)表示能夠執行下一次循環了。當定時器沒有執行的時候標記永遠是false,在開頭被return掉
canRun = true;
}, 500);
};
}
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener('resize', throttle(sayHi));
複製代碼
2. 使用場景:
節流:滾動加載更多、搜索框搜的索聯想功能、高頻點擊、表單重複提交……
防抖:搜索框搜索輸入,並在輸入完之後自動搜索、手機號,郵箱驗證輸入檢測、窗口大小 resize 變化後,再從新渲染。
移除生產環境的控制檯打印
。方案不少,esling+pre-commit、使用插件自動去除,插件包括babel-plugin-transform-remove-console、uglifyjs-webpack-plugin、terser-webpack-plugin。最後選擇了terser-webpack-plugin,腳手架vue-cli用這個插件來開啓緩存和多線程打包,無需安裝額外的插件,僅需在configureWebpack中設置terser插件的drop_console爲true便可。最好仍是養成良好的代碼習慣,在開發基本完成後去掉無用的console,vscode中的turbo console就蠻好的。
第三方庫的按需加載
。echarts,官方文檔裏是使用配置文件指定使用的模塊,另外一種使用babel-plugin-equire實現按需加載。element-ui使用babel-plugin-component實現按需引入。
公有樣式,好比對element-ui部分組件(如彈框、表格、下拉選框等)樣式的統一調整
。公共組件,好比date-picker、upload-file等在element-ui提供的組件基本上作進一步的封裝。自定義組件包括preview-file、搜索框等。
先後端數據交換方面,推進項目組使用藍湖、接口文檔,與後端同窗協商,規範後臺數據返回。
雅虎軍規提到的,避免css表達式、濾鏡,較少DOM操做,優化圖片、精靈圖,避免圖片空連接等
。
性能問題:頁面加載性能、動畫性能、操做性能
。Performance API,記錄性能數據。
winter重學前端 優化技術方案:
緩存:客戶端控制的強緩存策略
。
下降請求成本
:DNS 由客戶端控制,隔一段時間主動請求獲取域名IP,不走系統DNS(徹底看不懂)。TCP/TLS鏈接複用,服務器升級到HTTP2,儘可能合併域名。
減小請求數
:JS、CSS打包到HTML。JS控制圖片異步加載、懶加載。小型圖片使用data-uri。
較少傳輸體積
:儘可能使用SVG\gradient代替圖片。根據機型和網絡情況控制圖片清晰度。對低清晰度圖片使用銳化來提高體驗。設計上避免大型背景圖。
使用CDN加速
,內容分發網絡,是創建再承載網基礎上的虛擬分佈式網絡,可以將源站內容緩存到全國或全球的節點服務器上。用戶就近獲取內容,提升了資源的訪問速度,分擔源站壓力。
(二面、三面後的筆試)
一、手寫bind
二、手寫簡版promise,基礎架子,不用寫all、race等api 三、爬樓梯,leetcode-cn.com/problems/cl…(後面面試官問到了尾遞歸優化)
四、猴子吃香蕉leetcode-cn.com/problems/ko…
五、迴文字符串個數leetcode-cn.com/problems/pa…(這道題出現頻率很高,朋友面試的時候也遇到了,最長迴文子字符串)
二、說一下原型鏈,原型鏈實現繼承。
四、緩存相關(對比緩存?強緩存?對應請求頭)cookie有哪些屬性?
七、說說commonjs和esmodule?
一、項目相關問題,項目仍是須要好好準備。問得有點仔細
遇到過哪些難點?怎麼解決的?作過哪些優化?優化有量化嗎?用過哪些loader?plugin?你寫的這個插件實現了什麼?怎麼實現的?sourcemap原理知道嗎?(shabi了,由於瞄過一個博客,說知道一點,說了個vlq編碼,而後被問得很尷尬,不會直接說不會就好)
二、http和tcp、https、http2(隊頭阻塞?解決了哪些問題?哪有哪些問題未解決?tcp和udp?)。摘要算法和對稱加密、非對稱加密大概說一下?摘要和加密的區別?知道哪些加密算法?websocket的使用場景(socket.io降級)?
三、前端安全防範措施?xss攻擊和csrf攻擊?\
四、怎麼看待virtual dom?ast語法樹瞭解嗎?vue-loader作了哪些事情?vue diff?vue computed和watch區別?computed怎麼實現的緩存(dirty)?vue3雙向數據綁定實現?createRender?和vue2有哪些不一樣,提到了函數式編程,說下對函數式編程對的理解。(答得很垃圾,vue3瞭解很少,尤大的直播沒認真看)
五、對MVC (react) MVVM(vue)的瞭解
六、node相關問題,node的事件循環機制?stream兩種模式的區別?看過koa源碼都會以爲和express有很大不一樣,說一下?
七、你寫太小程序,說下和寫vue有什麼區別?而後我說setData會有性能問題(react中setState會有這個問題嗎?又給本身挖坑了) 說下jsbrige?
八、時針和分針的夾角? 九、爲何要離職?怎麼學習的?有什麼問題嗎?
解析:第 5 題
解析:第 6 題 一、項目相關問題? 四、團隊協做,之前的開發流程? 五、職業規劃? 六、有什麼問題嗎?
文中若有錯誤,歡迎在評論區指正,若是這篇文章幫到了你,歡迎點贊👍和關注😊