1.11 setState到底是異步還是同步
有時(shí)表現(xiàn)出異步,有時(shí)表現(xiàn)出同步
setState 只在合成事件和鉤子函數(shù)中是“異步”的,在原生事件和 setTimeout 中都是同步的。
setState 的異步并不是說內(nèi)部由異步代碼實(shí)現(xiàn),其實(shí)本身執(zhí)行的過程和代碼都是同步的,只是合成事件和鉤子函數(shù)的調(diào)用順序在更新之前,導(dǎo)致在合成事件和鉤子函數(shù)中沒法立馬拿到更新后的值,形成了所謂的“異步”,當(dāng)然可以通過第二個(gè)參數(shù) setState(partialState, callback)中的 callback 拿到更新后的結(jié)果。
setState 的批量更新優(yōu)化也是建立在“異步”(合成事件、鉤子函數(shù))之上的,在原生事件和setTimeout 中不會(huì)批量更新,在“異步”中如果對(duì)同一個(gè)值進(jìn)行多次 setState , setState 的批量更新策略會(huì)對(duì)其進(jìn)行覆蓋,取最后一次的執(zhí)行,如果是同時(shí) setState 多個(gè)不同的值,在更新時(shí)會(huì)對(duì)其進(jìn)行合并批量更新。
1.12 redux異步中間件之間的優(yōu)劣?
redux-thunk優(yōu)點(diǎn):
體積小: redux-thunk的實(shí)現(xiàn)方式很簡單,只有不到20行代碼
使用簡單: redux-thunk沒有引入像redux-saga或者redux-observable額外的范式,上手簡單
redux-thunk缺陷:
樣板代碼過多: 與redux本身一樣,通常一個(gè)請(qǐng)求需要大量的代碼,而且很多都是重復(fù)性質(zhì)的
耦合嚴(yán)重: 異步操作與redux的action偶合在一起,不方便管理
功能孱弱: 有一些實(shí)際開發(fā)中常用的功能需要自己進(jìn)行封裝
redux-saga優(yōu)點(diǎn):
異步解耦: 異步操作被被轉(zhuǎn)移到單獨(dú) saga.js 中,不再是摻雜在 action.js 或 component.js 中
action擺脫thunk function: dispatch 的參數(shù)依然是一個(gè)純粹的 action (FSA),而不是充滿 “黑魔法” thunk function
異常處理: 受益于 generator function 的 saga 實(shí)現(xiàn),代碼異常/請(qǐng)求失敗 都可以直接通過try/catch 語法直接捕獲處理
功能強(qiáng)大: redux-saga提供了大量的Saga 輔助函數(shù)和Effect 創(chuàng)建器供開發(fā)者使用,開發(fā)者無須封裝或者簡單封裝即可使用
靈活: redux-saga可以將多個(gè)Saga可以串行/并行組合起來,形成一個(gè)非常實(shí)用的異步flow
易測試,提供了各種case的測試方案,包括mock task,分支覆蓋等等
redux-saga缺陷:
額外的學(xué)習(xí)成本: redux-saga不僅在使用難以理解的 generator function,而且有數(shù)十個(gè)API,學(xué)習(xí)成本遠(yuǎn)超redux-thunk,最重要的是你的額外學(xué)習(xí)成本是只服務(wù)于這個(gè)庫的,與redux-observable不同,redux-observable雖然也有額外學(xué)習(xí)成本但是背后是rxjs和一整套思想
體積龐大: 體積略大,代碼近2000行,min版25KB左右
功能過剩: 實(shí)際上并發(fā)控制等功能很難用到,但是我們依然需要引入這些代碼
ts支持不友好: yield無法返回TS類型
redux-observable優(yōu)點(diǎn):
功能最強(qiáng): 由于背靠rxjs這個(gè)強(qiáng)大的響應(yīng)式編程的庫,借助rxjs的操作符,你可以幾乎做任何你能想到的異步處理
背靠rxjs: 由于有rxjs的加持,如果你已經(jīng)學(xué)習(xí)了rxjs,redux-observable的學(xué)習(xí)成本并不高,而且隨著
rxjs的升級(jí)redux-observable也會(huì)變得更強(qiáng)大
redux-observable缺陷:
學(xué)習(xí)成本奇高: 如果你不會(huì)rxjs,則需要額外學(xué)習(xí)兩個(gè)復(fù)雜的庫
社區(qū)一般: redux-observable的下載量只有redux-saga的1/5,社區(qū)也不夠活躍,在復(fù)雜異步流中間件
這個(gè)層面redux-saga仍處于領(lǐng)導(dǎo)地位
1.13 state 和 props 區(qū)別是啥?
props和state是普通的 JS 對(duì)象。雖然它們都包含影響渲染輸出的信息,但是它們?cè)诮M件方面的功能是不同的。即
- state 是組件自己管理數(shù)據(jù),控制自己的狀態(tài),可變
- props 是外部傳入的數(shù)據(jù)參數(shù),不可變;
- 沒有state的叫做無狀態(tài)組件,有state的叫做有狀態(tài)組件;
- 多用 props,少用 state,也就是多寫無狀態(tài)組件。
1.14 當(dāng)調(diào)用setState時(shí),React render 是如何工作的?
虛擬 DOM 渲染:當(dāng)render方法被調(diào)用時(shí),它返回一個(gè)新的組件的虛擬 DOM 結(jié)構(gòu)。當(dāng)調(diào)用setState()時(shí),render會(huì)被再次調(diào)用,因?yàn)槟J(rèn)情況下shouldComponentUpdate總是返回true,所以默認(rèn)情況下React 是沒有優(yōu)化的。
原生 DOM 渲染:React 只會(huì)在虛擬DOM中修改真實(shí)DOM節(jié)點(diǎn),而且修改的次數(shù)非常少——這是很棒的React特性,它優(yōu)化了真實(shí)DOM的變化,使React變得更快。
1.15 hooks
Hooks簡介
React的組件創(chuàng)建方式,一種是類組件,一種是純函數(shù)組件
- 純函數(shù)組件沒有狀態(tài)
- 純函數(shù)組件沒有生命周期
- 純函數(shù)組件沒有this
使用Hooks的優(yōu)點(diǎn):
- 告別難以理解的Class( this 和 生命周期 的痛點(diǎn))
- 解決業(yè)務(wù)邏輯難以拆分的問題
- 使?fàn)顟B(tài)邏輯復(fù)用變得簡單可行
- 函數(shù)組件從設(shè)計(jì)思想上來看更加契合React的理念
Hooks并非萬能:
- Hooks暫時(shí)還不能完全的為函數(shù)組件補(bǔ)齊類組件地能力(如生命周期的getSnapshotBeforeUpdate、componentDidCatch方法暫時(shí)還未實(shí)現(xiàn))
- 將類組件的復(fù)雜變成函數(shù)組件的輕量,可能使用者并不能很好地消化這種復(fù)雜
- Hooks在使用層面有著嚴(yán)格地規(guī)則約束
Hook函數(shù)(9種)
- useState():狀態(tài)鉤子
- useContext():共享狀態(tài)鉤子
- useEffect():副作用鉤子
- useReducer():Action鉤子
- userRefef():Ref Hook可以在函數(shù)組件中存儲(chǔ)、查找組件內(nèi)的標(biāo)簽或任意其它數(shù)據(jù)
- useMemo(): 主要用來解決使用React hooks產(chǎn)生的無用渲染的性能問題
- useCallback(): 主要是為了性能的優(yōu)化
- useLayoutEffect() :和useEffect相同,都是用來執(zhí)行副作用,但是它會(huì)在所有的DOM變更之后同步調(diào)用effect。useLayoutEffect和useEffect最大的區(qū)別就是一個(gè)是同步,一個(gè)是異步。
- useImperativeHandle(): 可以在使用 ref 時(shí)自定義暴露給父組件的實(shí)例值。
自定義Hooks
自定義 Hooks:是一個(gè)函數(shù),其名稱以 “use” 開頭,函數(shù)內(nèi)部可以調(diào)用其他的 Hook
自定義Hooks:可以封裝狀態(tài),能夠更好的實(shí)現(xiàn)狀態(tài)共享
打包工具
1.1 前端為什么要進(jìn)行打包和構(gòu)建
- 體積更?。═ree-Shaking、壓縮、合并),加載更快
- 編譯高級(jí)語言和語法(TS,ES6+,模塊化,scss)
- 兼容性和錯(cuò)誤檢查(Polyfill、postcss、eslint)
- 統(tǒng)一、高效的開發(fā)環(huán)境
- 統(tǒng)一的構(gòu)建流程和產(chǎn)出標(biāo)準(zhǔn)
- 集成公司構(gòu)建規(guī)范(提測、上線等)
1.2 如何提高webpack的構(gòu)建速度
- 優(yōu)化babel-loader 開啟緩存
- 使用module中的Noparse,不去解析屬性值代表的庫的依賴(需要在webpack.config.js的module節(jié)點(diǎn)添加noParse配置,使用|分割)
- 可以使用webpack內(nèi)置插件lgnorePlugin插件(作用:忽略第三方包指定目錄,讓這些指定目錄不要被打包進(jìn)去)
- 使用happyPack多進(jìn)程打包(需要下載)
- 使用parallelUgligyPlugin多進(jìn)程壓縮js(默認(rèn)使用uglifyJs來壓縮代碼,單進(jìn)程)
1.3 代碼分割的本質(zhì)是什么?
- 代碼分割的本質(zhì)就是在源代碼直接上線和達(dá)成唯一腳本main.bundle.js這兩種極端方案之間的一種更適合實(shí)際場景的中間狀態(tài)。
- 源碼直接上線:雖然過程可控,但是http請(qǐng)求多,性能開銷大。
- 打包成唯一腳本:服務(wù)器壓力小,但是頁面空白期長,用戶體驗(yàn)不好。
1.4webpack的基本功能有哪些?
| 名稱 | 內(nèi)容 |
|---|---|
| 代碼轉(zhuǎn)換 | typescript編譯成JavaScript、scss編輯成css |
| 文件優(yōu)化 | 壓縮JavaScript、css、html、壓縮合并圖片 |
| 代碼分割 | 提取多個(gè)頁面的公共代碼、提取首屏不需要執(zhí)行部分的代碼讓其異步加載 |
| 模塊合并 | 采用模塊化的項(xiàng)目有很多模塊和文件,需要構(gòu)建功能把模塊分類合并成一個(gè)文件 |
| 自動(dòng)刷新 | 監(jiān)聽本地源代碼的變化,自動(dòng)構(gòu)建,刷新瀏覽器 |
| 代碼校驗(yàn) | 在代碼被提交到倉庫前需要檢測代碼是否符合規(guī)范,以及單元測試是否通過 |
| 自動(dòng)發(fā)布 | 更新完代碼后,自動(dòng)構(gòu)建出線上發(fā)布代碼并傳輸給發(fā)布系統(tǒng) |
1.5 文件指紋是什么?
文件指紋是打包之后的文件后綴名。
chunkhash:和webpack打包的chunk有關(guān),不同的entry會(huì)生出不同的chunkhash。
js后綴名:filename:'\[name]\[chunkhash:8].js',
contenthash:根據(jù)文件內(nèi)容來定義hash,文件內(nèi)容不變,則其不變。
css后綴名:filename:'\[name]\[contenthash:8].css',
hash:和整個(gè)項(xiàng)目構(gòu)建有關(guān),只要項(xiàng)目文件有修改,整個(gè)構(gòu)建的hash值就會(huì)修改。
img后綴名:name:'\[name]\[hash:8].\[ext]'
1.6 為什么說vite比webpack更快?
- webpack會(huì)先打包,然后啟動(dòng)開發(fā)服務(wù)器,請(qǐng)求服務(wù)器時(shí)直接給予打包結(jié)果。
- vite是直接啟動(dòng)開發(fā)服務(wù)器,請(qǐng)求哪個(gè)模塊再對(duì)該模塊進(jìn)行實(shí)時(shí)編譯。
- vite在啟動(dòng)的時(shí)候不需要打包,意味著不需要分析模塊的依賴、不需要編譯,因此啟動(dòng)速度非???。
- 當(dāng)瀏覽器請(qǐng)求某個(gè)模塊時(shí),再根據(jù)需要對(duì)模塊內(nèi)容進(jìn)行編譯。這種按需動(dòng)態(tài)編譯的方式,極大的縮減了編譯時(shí)間,項(xiàng)目越復(fù)雜、模塊越多,vite的優(yōu)勢越明顯。
- 在HMR方面,當(dāng)改動(dòng)了一個(gè)模塊后,僅需讓瀏覽器重新請(qǐng)求該模塊即可,不像webpack那樣需要把該模塊的相關(guān)依賴模塊全部編譯一次,效率更高。
- 當(dāng)需要打包到生產(chǎn)環(huán)境時(shí),vite使用傳統(tǒng)的rollup進(jìn)行打包,因此,vite的主要優(yōu)勢在開發(fā)階段。另外,由于vite利用的是ES Module,因此在代碼中不可以使用CommonJS
1.7 vite工作原理
vite是一種現(xiàn)代化的前端開發(fā)工具,其工作原理主要分為以下幾個(gè)步驟
- 基于ESM構(gòu)建:Vite作為一款基于ESM的前端構(gòu)建工具,通過ES模塊提供的動(dòng)態(tài)導(dǎo)入功能來實(shí)現(xiàn)快速的開發(fā)和構(gòu)建。
- 零配置開發(fā):Vite允許開發(fā)者在不需要任何配置的情況下啟動(dòng)一個(gè)服務(wù)器進(jìn)行開發(fā),通過對(duì)文件的即時(shí)編譯和緩存,來提高開發(fā)效率。
- 基于瀏覽器原生的ESM加載:Vite將所有文件視為ES模塊,并且在開發(fā)時(shí)會(huì)直接從源代碼加載模塊,而不是打包后的文件,從而可以避免打包的過程帶來的性能損失。
- 按需編譯和緩存:Vite會(huì)按需編譯和緩存依賴項(xiàng),只有當(dāng)需要更新時(shí)才會(huì)進(jìn)行重新編譯,緩存讓開發(fā)者可以忽略無關(guān)的代碼變化。
- 插件化架構(gòu):Vite的插件化架構(gòu)可以方便地?cái)U(kuò)展其功能,例如使用插件來處理CSS、處理圖片、壓縮源代碼等等。
1.8 vite核心原理
- Vite其核心原理是利用瀏覽器現(xiàn)在已經(jīng)支持ES6的import,碰見import就會(huì)發(fā)送一個(gè)HTTP請(qǐng)求去加載文件。
- Vite整個(gè)過程中沒有對(duì)文件進(jìn)行打包編譯,做到了真正的按需加載,所以其運(yùn)行速度比原始的webpack開發(fā)編譯速度快出許多!
特點(diǎn):
- 快速的冷啟動(dòng):基于Esbuild的依賴進(jìn)行預(yù)編譯優(yōu)化 (Esbuild 打包速度太快了,比類似的工具快10~100倍 )
- 增加緩存策略:源碼模塊使用協(xié)商緩存,依賴模塊使用強(qiáng)緩;因此一旦被緩存它們將不需要再次請(qǐng)求
- HMR(熱更新):當(dāng)修改代碼時(shí),HMR 能夠在不刷新頁面的情況下,把頁面中發(fā)生變化的模塊,替換成新的模塊,同時(shí)不影響其他模塊的正常運(yùn)作
- 基于 Rollup 打包:生產(chǎn)環(huán)境下由于esbuild對(duì)css和代碼分割并使用Rollup進(jìn)行打包
- 高效的熱更新:基于ESM實(shí)現(xiàn),同時(shí)利用HTTP頭來加速整個(gè)頁面的重新加載
1.9 Vite 冷啟動(dòng)為什么快
vite 運(yùn)行 Dev 命令后只做了兩件事情
- 啟動(dòng)本地服務(wù)器并注冊(cè)了一些中間件
- 使用 ESbuild 預(yù)構(gòu)建模塊
1.10 vite生產(chǎn)環(huán)境缺點(diǎn)
Vite 在是直接把轉(zhuǎn)化后的 es module 的JavaScript,扔給瀏覽器,讓瀏覽器根據(jù)依賴關(guān)系,自己去加載依賴
-
那有人就會(huì)說了,那放到 生產(chǎn)環(huán)境 時(shí),是不是可以不打包,直接在開個(gè) Vite 服務(wù)就行,反正瀏覽器會(huì)自己去根據(jù)依賴關(guān)系去自己加載依賴。答案是不行的,為啥呢:
1、你代碼是放在服務(wù)器的,過多的瀏覽器加載依賴肯定會(huì)引起更多的網(wǎng)絡(luò)請(qǐng)求
2、為了在生產(chǎn)環(huán)境中獲得最佳的加載性能,最好還是將代碼進(jìn)行 tree-shaking、懶加載和 chunk 分割、CSS處理,這些優(yōu)化操作,目前 esbuild 還不怎么完善
1.11 vite和webpack優(yōu)缺點(diǎn)對(duì)比
- 更快的啟動(dòng)時(shí)間和更新速度
- 更好的開發(fā)體驗(yàn):自動(dòng)打開瀏覽器、自動(dòng)刷新頁面 配置簡單。
- 不需要過多的配置就可以搭建基本的開發(fā)環(huán)境 更少的依賴。
- 借助原生的ES模塊
- 避免了過多的額外依賴
缺點(diǎn):
- vite的構(gòu)建技術(shù)主要用于中小型項(xiàng)目,對(duì)于大型項(xiàng)目的支持不如webpack
- vite主要是針對(duì)vue3的單頁面應(yīng)用,對(duì)于多頁面應(yīng)用、ssr應(yīng)用、自定義流程應(yīng)用不如webpack
- 開發(fā)環(huán)境首屏加載慢,懶加載慢
- vite由于基于原生ES模塊,不支持commonJs;webpack關(guān)注兼容性,vite關(guān)注瀏覽器端的開發(fā)體驗(yàn),vite的生態(tài)還不如webpack