前端基礎(chǔ)之React(二)

1.11 setState到底是異步還是同步

有時(shí)表現(xiàn)出異步,有時(shí)表現(xiàn)出同步

  1. setState 只在合成事件和鉤子函數(shù)中是“異步”的,在原生事件和 setTimeout 中都是同步的。

  2. setState 的異步并不是說內(nèi)部由異步代碼實(shí)現(xiàn),其實(shí)本身執(zhí)行的過程和代碼都是同步的,只是合成事件和鉤子函數(shù)的調(diào)用順序在更新之前,導(dǎo)致在合成事件和鉤子函數(shù)中沒法立馬拿到更新后的值,形成了所謂的“異步”,當(dāng)然可以通過第二個(gè)參數(shù) setState(partialState, callback)中的 callback 拿到更新后的結(jié)果。

  3. 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種)

  1. useState():狀態(tài)鉤子
  2. useContext():共享狀態(tài)鉤子
  3. useEffect():副作用鉤子
  4. useReducer():Action鉤子
  5. userRefef():Ref Hook可以在函數(shù)組件中存儲(chǔ)、查找組件內(nèi)的標(biāo)簽或任意其它數(shù)據(jù)
  6. useMemo(): 主要用來解決使用React hooks產(chǎn)生的無用渲染的性能問題
  7. useCallback(): 主要是為了性能的優(yōu)化
  8. useLayoutEffect() :和useEffect相同,都是用來執(zhí)行副作用,但是它會(huì)在所有的DOM變更之后同步調(diào)用effect。useLayoutEffect和useEffect最大的區(qū)別就是一個(gè)是同步,一個(gè)是異步。
  9. 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)建

  1. 體積更?。═ree-Shaking、壓縮、合并),加載更快
  2. 編譯高級(jí)語言和語法(TS,ES6+,模塊化,scss)
  3. 兼容性和錯(cuò)誤檢查(Polyfill、postcss、eslint)
  4. 統(tǒng)一、高效的開發(fā)環(huán)境
  5. 統(tǒng)一的構(gòu)建流程和產(chǎn)出標(biāo)準(zhǔn)
  6. 集成公司構(gòu)建規(guī)范(提測、上線等)

1.2 如何提高webpack的構(gòu)建速度

  1. 優(yōu)化babel-loader 開啟緩存
  2. 使用module中的Noparse,不去解析屬性值代表的庫的依賴(需要在webpack.config.js的module節(jié)點(diǎn)添加noParse配置,使用|分割)
  3. 可以使用webpack內(nèi)置插件lgnorePlugin插件(作用:忽略第三方包指定目錄,讓這些指定目錄不要被打包進(jìn)去)
  4. 使用happyPack多進(jìn)程打包(需要下載)
  5. 使用parallelUgligyPlugin多進(jìn)程壓縮js(默認(rèn)使用uglifyJs來壓縮代碼,單進(jìn)程)

1.3 代碼分割的本質(zhì)是什么?

  1. 代碼分割的本質(zhì)就是在源代碼直接上線和達(dá)成唯一腳本main.bundle.js這兩種極端方案之間的一種更適合實(shí)際場景的中間狀態(tài)。
  2. 源碼直接上線:雖然過程可控,但是http請(qǐng)求多,性能開銷大。
  3. 打包成唯一腳本:服務(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更快?

  1. webpack會(huì)先打包,然后啟動(dòng)開發(fā)服務(wù)器,請(qǐng)求服務(wù)器時(shí)直接給予打包結(jié)果。
  2. vite是直接啟動(dòng)開發(fā)服務(wù)器,請(qǐng)求哪個(gè)模塊再對(duì)該模塊進(jìn)行實(shí)時(shí)編譯。
  3. vite在啟動(dòng)的時(shí)候不需要打包,意味著不需要分析模塊的依賴、不需要編譯,因此啟動(dòng)速度非???。
  4. 當(dāng)瀏覽器請(qǐng)求某個(gè)模塊時(shí),再根據(jù)需要對(duì)模塊內(nèi)容進(jìn)行編譯。這種按需動(dòng)態(tài)編譯的方式,極大的縮減了編譯時(shí)間,項(xiàng)目越復(fù)雜、模塊越多,vite的優(yōu)勢越明顯。
  5. 在HMR方面,當(dāng)改動(dòng)了一個(gè)模塊后,僅需讓瀏覽器重新請(qǐng)求該模塊即可,不像webpack那樣需要把該模塊的相關(guān)依賴模塊全部編譯一次,效率更高。
  6. 當(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è)步驟

  1. 基于ESM構(gòu)建:Vite作為一款基于ESM的前端構(gòu)建工具,通過ES模塊提供的動(dòng)態(tài)導(dǎo)入功能來實(shí)現(xiàn)快速的開發(fā)和構(gòu)建。
  2. 零配置開發(fā):Vite允許開發(fā)者在不需要任何配置的情況下啟動(dòng)一個(gè)服務(wù)器進(jìn)行開發(fā),通過對(duì)文件的即時(shí)編譯和緩存,來提高開發(fā)效率。
  3. 基于瀏覽器原生的ESM加載:Vite將所有文件視為ES模塊,并且在開發(fā)時(shí)會(huì)直接從源代碼加載模塊,而不是打包后的文件,從而可以避免打包的過程帶來的性能損失。
  4. 按需編譯和緩存:Vite會(huì)按需編譯和緩存依賴項(xiàng),只有當(dāng)需要更新時(shí)才會(huì)進(jìn)行重新編譯,緩存讓開發(fā)者可以忽略無關(guān)的代碼變化。
  5. 插件化架構(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):

  1. 快速的冷啟動(dòng):基于Esbuild的依賴進(jìn)行預(yù)編譯優(yōu)化 (Esbuild 打包速度太快了,比類似的工具快10~100倍 )
  2. 增加緩存策略:源碼模塊使用協(xié)商緩存,依賴模塊使用強(qiáng)緩;因此一旦被緩存它們將不需要再次請(qǐng)求
  3. HMR(熱更新):當(dāng)修改代碼時(shí),HMR 能夠在不刷新頁面的情況下,把頁面中發(fā)生變化的模塊,替換成新的模塊,同時(shí)不影響其他模塊的正常運(yùn)作
  4. 基于 Rollup 打包:生產(chǎn)環(huán)境下由于esbuild對(duì)css和代碼分割并使用Rollup進(jìn)行打包
  5. 高效的熱更新:基于ESM實(shí)現(xiàn),同時(shí)利用HTTP頭來加速整個(gè)頁面的重新加載

1.9 Vite 冷啟動(dòng)為什么快

vite 運(yùn)行 Dev 命令后只做了兩件事情

  1. 啟動(dòng)本地服務(wù)器并注冊(cè)了一些中間件
  2. 使用 ESbuild 預(yù)構(gòu)建模塊

1.10 vite生產(chǎn)環(huán)境缺點(diǎn)

  1. Vite 在是直接把轉(zhuǎn)化后的 es module 的JavaScript,扔給瀏覽器,讓瀏覽器根據(jù)依賴關(guān)系,自己去加載依賴

  2. 那有人就會(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
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容