強制緩存與協(xié)商緩存
強制緩存不會向服務(wù)器發(fā)送請求岗喉,直接在緩存資源中讀取赴肚,返回狀態(tài)嗎200
協(xié)商緩存會向服務(wù)器發(fā)送請求锈颗,服務(wù)器會根據(jù)請求頭的參數(shù)來判斷是否命中協(xié)商緩存,如果命中則返回304采蚀,并帶上新的response header通知瀏覽器從緩存中讀取資源
強制緩存:
Expires:response header里的過期時間疲牵,瀏覽器再次加載資源時承二,如果在這個過期時間內(nèi),則命中強緩存纲爸。
Cache-Control****:當值設(shè)為max-age=300時亥鸠,則代表在這個請求正確返回時間(瀏覽器也會記錄下來)的5分鐘內(nèi)再次加載資源,就會命中強緩存识啦。
cache-control****除了該字段外负蚊,還有下面幾個比較常用的設(shè)置值:
-no-cache****:不使用本地緩存。需要使用緩存協(xié)商颓哮,先與服務(wù)器確認返回的響應(yīng)是否被更改家妆,如果之前的響應(yīng)中存在ETag,那么請求的時候會與服務(wù)端驗證冕茅,如果資源未被更改伤极,則可以避免重新下載。
-no-store****:直接禁止瀏覽器緩存數(shù)據(jù)姨伤,每次用戶請求該資源哨坪,都會向服務(wù)器發(fā)送一個請求,每次都會下載完整的資源乍楚。
-public****:可以被所有的用戶緩存当编,包括終端用戶和CDN等中間代理服務(wù)器。
-private****:只能被終端用戶的瀏覽器緩存徒溪,不允許CDN等中繼緩存服務(wù)器對其緩存忿偷。
協(xié)商緩存
Last-Modify/If-Modify-Since:瀏覽器第一次請求一個資源的時候,服務(wù)器返回的header中會加上Last-Modify臊泌,Last-modify是一個時間標識該資源的最后修改時間鲤桥;當瀏覽器再次請求該資源時,request的請求頭中會包含If-Modify-Since缺虐,該值為緩存之前返回的Last-Modify芜壁。服務(wù)器收到If-Modify-Since后,根據(jù)資源的最后修改時間判斷是否命中緩存
Etag****:web服務(wù)器響應(yīng)請求時高氮,告訴瀏覽器當前資源在服務(wù)器的唯一標識(生成規(guī)則由服務(wù)器決定)慧妄。
If-None-Match****:當資源過期時(使用Cache-Control標識的max-age),發(fā)現(xiàn)資源具有Etage聲明剪芍,則再次向web服務(wù)器請求時帶上頭If-None-Match (Etag的值)塞淹。web服務(wù)器收到請求后發(fā)現(xiàn)有頭If-None-Match 則與被請求資源的相應(yīng)校驗串進行比對,決定是否命中協(xié)商緩存罪裹;
ETag****和Last-Modified的作用和用法饱普,他們的區(qū)別:
1.Etag要優(yōu)于Last-Modified运挫。Last-Modified的時間單位是秒,如果某個文件在1秒內(nèi)改變了多次套耕,那么他們的Last-Modified其實并沒有體現(xiàn)出來修改谁帕,但是Etag每次都會改變確保了精度;
2.在性能上冯袍,Etag要遜于Last-Modified匈挖,畢竟Last-Modified只需要記錄時間,而Etag需要服務(wù)器通過算法來計算出一個hash值康愤;
3.在優(yōu)先級上儡循,服務(wù)器校驗優(yōu)先考慮Etag。
瀏覽器緩存過程
1.瀏覽器第一次加載資源征冷,服務(wù)器返回200择膝,瀏覽器將資源文件從服務(wù)器上請求下載下來,并把response header及該請求的返回時間一并緩存检激;
2.下一次加載資源時肴捉,先比較當前時間和上一次返回200時的時間差,如果沒有超過cache-control設(shè)置的max-age呵扛,則沒有過期每庆,命中強緩存,不發(fā)請求直接從本地緩存讀取該文件(如果瀏覽器不支持HTTP1.1今穿,則用expires判斷是否過期)缤灵;如果時間過期,則向服務(wù)器發(fā)送header帶有If-None-Match和If-Modified-Since的請求
3.服務(wù)器收到請求后蓝晒,優(yōu)先根據(jù)Etag的值判斷被請求的文件有沒有做修改腮出,Etag值一致則沒有修改,命中協(xié)商緩存芝薇,返回304胚嘲;如果不一致則有改動,直接返回新的資源文件帶上新的Etag值并返回200洛二;馋劈;
4.如果服務(wù)器收到的請求沒有Etag值,則將If-Modified-Since和被請求文件的最后修改時間做比對晾嘶,一致則命中協(xié)商緩存妓雾,返回304;不一致則返回新的last-modified和文件并返回200垒迂;械姻;
宏任務(wù)與微任務(wù)
宏任務(wù):I/O setTimeout, setInterval setImmediate requestAnimationFrame
微任務(wù):process.nextTick MutationObserver Promise.then catch finally
執(zhí)行順序:同步任務(wù) –-> 微任務(wù) --> 宏任務(wù)
React****中什么是受控組件和非控組件?
(1)受控組件 在使用表單來收集用戶輸入時机断,例如<input><select><textearea>等元素都要綁定一個change事件楷拳,當表單的狀態(tài)發(fā)生變化绣夺,就會觸發(fā)onChange事件,更新組件的state欢揖。這種組件在React中被稱為受控組件陶耍,在受控組件中,組件渲染出的狀態(tài)與它的value或checked屬性相對應(yīng)浸颓,react通過這種方式消除了組件的局部狀態(tài)物臂,使整個狀態(tài)可控旺拉。react官方推薦使用受控表單組件产上。
受控組件更新state的流程:
- 可以通過初始state中設(shè)置表單的默認值
- 每當表單的值發(fā)生變化時,調(diào)用onChange事件處理器
- 事件處理器通過事件對象e拿到改變后的狀態(tài)蛾狗,并更新組件的state
- 一旦通過setState方法更新state晋涣,就會觸發(fā)視圖的重新渲染,完成表單組件的更新
受控組件缺陷: 表單元素的值都是由React組件進行管理沉桌,當有多個輸入框谢鹊,或者多個這種組件時,如果想同時獲取到全部的值就必須每個都要編寫事件處理函數(shù)留凭,這會讓代碼看著很臃腫佃扼,所以為了解決這種情況,出現(xiàn)了非受控組件蔼夜。
(2)非受控組件 如果一個表單組件沒有value props(單選和復選按鈕對應(yīng)的是checked props)時兼耀,就可以稱為非受控組件。在非受控組件中求冷,可以使用一個ref來從DOM獲得表單值瘤运。而不是為每個狀態(tài)更新編寫一個事件處理程序。
React官方的解釋:
要編寫一個非受控組件匠题,而不是為每個狀態(tài)更新都編寫數(shù)據(jù)處理函數(shù)拯坟,你可以使用 ref來從 DOM 節(jié)點中獲取表單數(shù)據(jù)。 因為非受控組件將真實數(shù)據(jù)儲存在 DOM 節(jié)點中韭山,所以在使用非受控組件時郁季,有時候反而更容易同時集成 React 和非 React 代碼。如果你不介意代碼美觀性钱磅,并且希望快速編寫代碼梦裂,使用非受控組件往往可以減少你的代碼量。否則续搀,你應(yīng)該使用受控組件塞琼。
例如,下面的代碼在非受控組件中接收單個屬性:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={(input) => this.input = input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
復制代碼
總結(jié): 頁面中所有輸入類的DOM如果是現(xiàn)用現(xiàn)取的稱為非受控組件禁舷,而通過setState將輸入的值維護到了state中彪杉,需要時再從state中取出毅往,這里的數(shù)據(jù)就受到了state的控制,稱為受控組件派近。
React****事件機制
React并不是將click事件綁定到了div的真實DOM上攀唯,而是在document處監(jiān)聽了所有的事件,當事件發(fā)生并且冒泡到document處的時候渴丸,React將事件內(nèi)容封裝并交由真正的處理函數(shù)運行侯嘀。這樣的方式不僅僅減少了內(nèi)存的消耗,還能在組件掛在銷毀時統(tǒng)一訂閱和移除事件谱轨。
除此之外戒幔,冒泡到document上的事件也不是原生的瀏覽器事件,而是由react自己實現(xiàn)的合成事件(SyntheticEvent)土童。因此如果不想要是事件冒泡的話應(yīng)該調(diào)用event.preventDefault()方法诗茎,而不是調(diào)用event.stopProppagation()方法。 JSX 上寫的事件并沒有綁定在對應(yīng)的真實 DOM 上献汗,而是通過事件代理的方式敢订,將所有的事件都統(tǒng)一綁定在了 document 上。這樣的方式不僅減少了內(nèi)存消耗,還能在組件掛載銷毀時統(tǒng)一訂閱和移除事件。
另外冒泡到 document 上的事件也不是原生瀏覽器事件祖灰,而是 React 自己實現(xiàn)的合成事件(SyntheticEvent)。因此我們?nèi)绻幌胍录芭莸脑挿瘢{(diào)用 event.stopPropagation 是無效的,而應(yīng)該調(diào)用 event.preventDefault泊业。
實現(xiàn)合成事件的目的如下:
- 合成事件首先抹平了瀏覽器之間的兼容問題把沼,另外這是一個跨瀏覽器原生事件包裝器,賦予了跨瀏覽器開發(fā)的能力吁伺;
- 對于原生瀏覽器事件來說饮睬,瀏覽器會給監(jiān)聽器創(chuàng)建一個事件對象。如果你有很多的事件監(jiān)聽篮奄,那么就需要分配很多的事件對象捆愁,造成高額的內(nèi)存分配問題。但是對于合成事件來說窟却,有一個事件池專門來管理它們的創(chuàng)建和銷毀昼丑,當事件需要被使用時,就會從池子中復用對象夸赫,事件回調(diào)結(jié)束后菩帝,就會銷毀事件對象上的屬性,從而便于下次復用事件對象。
React 高階組件呼奢、Render props宜雀、hooks 有什么區(qū)別,為什么要不斷迭代
這三者是目前react解決代碼復用的主要方式:
- 高階組件(HOC)是 React 中用于復用組件邏輯的一種高級技巧握础。HOC 自身不是 React API 的一部分辐董,它是一種基于 React 的組合特性而形成的設(shè)計模式。具體而言禀综,高階組件是參數(shù)為組件简烘,返回值為新組件的函數(shù)。
- render props是指一種在 React 組件之間使用一個值為函數(shù)的 prop 共享代碼的簡單技術(shù)定枷,更具體的說孤澎,render prop 是一個用于告知組件需要渲染什么內(nèi)容的函數(shù) prop。
- 通常依鸥,render props 和高階組件只渲染一個子節(jié)點亥至。讓 Hook 來服務(wù)這個使用場景更加簡單。這兩種模式仍有用武之地贱迟,(例如,一個虛擬滾動條組件或許會有一個 renderltem 屬性絮供,或是一個可見的容器組件或許會有它自己的 DOM 結(jié)構(gòu))衣吠。但在大部分場景下,Hook 足夠了壤靶,并且能夠幫助減少嵌套缚俏。
(1)HOC 官方解釋∶
高階組件(HOC)是 React 中用于復用組件邏輯的一種高級技巧。HOC 自身不是 React API 的一部分贮乳,它是一種基于 React 的組合特性而形成的設(shè)計模式忧换。
簡言之,HOC是一種組件的設(shè)計模式向拆,HOC接受一個組件和額外的參數(shù)(如果需要)亚茬,返回一個新的組件。HOC 是純函數(shù)浓恳,沒有副作用刹缝。
// hoc的定義
function withSubscription(WrappedComponent, selectData) {
return class extends React.Component {
constructor(props) {
super(props);
this.state = {
data: selectData(DataSource, props)
};
}
// 一些通用的邏輯處理
render() {
// ... 并使用新數(shù)據(jù)渲染被包裝的組件!
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
// 使用
const BlogPostWithSubscription = withSubscription(BlogPost,
(DataSource, props) => DataSource.getBlogPost(props.id));
復制代碼
HOC的優(yōu)缺點∶
- 優(yōu)點∶ 邏輯復用、不影響被包裹組件的內(nèi)部邏輯颈将。
- 缺點∶ hoc傳遞給被包裹組件的props容易和被包裹后的組件重名梢夯,進而被覆蓋
(2)Render props 官方解釋∶
"render prop"是指一種在 React 組件之間使用一個值為函數(shù)的 prop 共享代碼的簡單技術(shù)
具有render prop 的組件接受一個返回React元素的函數(shù),將render的渲染邏輯注入到組件內(nèi)部晴圾。在這里颂砸,"render"的命名可以是任何其他有效的標識符。
// DataProvider組件內(nèi)部的渲染邏輯如下
class DataProvider extends React.Components {
state = {
name: 'Tom'
}
render() {
return (
<div>
<p>共享數(shù)據(jù)組件自己內(nèi)部的渲染邏輯</p>
{ this.props.render(this.state) }
</div>
);
}
}
// 調(diào)用方式
<DataProvider render={data => (
<h1>Hello {data.name}</h1>
)}/>
復制代碼
由此可以看到,render props的優(yōu)缺點也很明顯∶
- 優(yōu)點:數(shù)據(jù)共享人乓、代碼復用梗醇,將組件內(nèi)的state作為props傳遞給調(diào)用者,將渲染邏輯交給調(diào)用者撒蟀。
- 缺點:無法在 return 語句外訪問數(shù)據(jù)叙谨、嵌套寫法不夠優(yōu)雅
(3)Hooks 官方解釋∶
Hook是 React 16.8 的新增特性。它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性保屯。通過自定義hook手负,可以復用代碼邏輯。
// 自定義一個獲取訂閱數(shù)據(jù)的hook
function useSubscription() {
const data = DataSource.getComments();
return [data];
}
//
function CommentList(props) {
const {data} = props;
const [subData] = useSubscription();
...
}
// 使用
<CommentList data='hello' />
復制代碼
以上可以看出姑尺,hook解決了hoc的prop覆蓋的問題竟终,同時使用的方式解決了render props的嵌套地獄的問題。hook的優(yōu)點如下∶
- 使用直觀切蟋;
- 解決hoc的prop 重名問題统捶;
- 解決render props 因共享數(shù)據(jù) 而出現(xiàn)嵌套地獄的問題;
- 能在return之外使用數(shù)據(jù)的問題柄粹。
需要注意的是:hook只能在組件頂層使用喘鸟,不可在分支語句中使用。
總結(jié)∶ Hoc驻右、render props和hook都是為了解決代碼復用的問題什黑,但是hoc和render props都有特定的使用場景和明顯的缺點。hook是react16.8更新的新的API堪夭,讓組件邏輯復用更簡潔明了愕把,同時也解決了hoc和render props的一些缺點。
對React-Fiber的理解森爽,它解決了什么問題恨豁?
React V15 在渲染時,會遞歸比對 VirtualDOM 樹爬迟,找出需要變動的節(jié)點橘蜜,然后同步更新它們, 一氣呵成雕旨。這個過程期間扮匠, React 會占據(jù)瀏覽器資源,這會導致用戶觸發(fā)的事件得不到響應(yīng)凡涩,并且會導致掉幀棒搜,導致用戶感覺到卡頓。
為了給用戶制造一種應(yīng)用很快的“假象”活箕,不能讓一個任務(wù)長期霸占著資源力麸。 可以將瀏覽器的渲染、布局、繪制克蚂、資源加載(例如 HTML 解析)闺鲸、事件響應(yīng)、腳本執(zhí)行視作操作系統(tǒng)的“進程”埃叭,需要通過某些調(diào)度策略合理地分配 CPU 資源摸恍,從而提高瀏覽器的用戶響應(yīng)速率, 同時兼顧任務(wù)執(zhí)行效率。
所以 React 通過Fiber 架構(gòu)赤屋,讓這個執(zhí)行過程變成可被中斷立镶。“適時”地讓出 CPU 執(zhí)行權(quán)类早,除了可以讓瀏覽器及時地響應(yīng)用戶的交互媚媒,還有其他好處:
- 分批延時對DOM進行操作,避免一次性操作大量 DOM 節(jié)點涩僻,可以得到更好的用戶體驗缭召;
- 給瀏覽器一點喘息的機會,它會對代碼進行編譯優(yōu)化(JIT)及進行熱代碼優(yōu)化逆日,或者對 reflow 進行修正嵌巷。
核心思想: Fiber 也稱協(xié)程或者纖程。它和線程并不一樣屏富,協(xié)程本身是沒有并發(fā)或者并行能力的(需要配合線程)晴竞,它只是一種控制流程的讓出機制。讓出 CPU 的執(zhí)行權(quán)狠半,讓 CPU 能在這段時間執(zhí)行其他的操作。渲染的過程可以被中斷颤难,可以將控制權(quán)交回瀏覽器神年,讓位給高優(yōu)先級的任務(wù),瀏覽器空閑后再恢復渲染行嗤。
哪些方法會觸發(fā) React 重新渲染已日?重新渲染 render 會做些什么?
(1)哪些方法會觸發(fā) react 重新渲染?
- setState****()方法被調(diào)用
setState 是 React 中最常用的命令栅屏,通常情況下飘千,執(zhí)行 setState 會觸發(fā) render。但是這里有個點值得關(guān)注栈雳,執(zhí)行 setState 的時候不一定會重新渲染护奈。當 setState 傳入 null 時,并不會觸發(fā) render哥纫。
class App extends React.Component {
state = {
a: 1
};
render() {
console.log("render");
return (
<React.Fragement>
<p>{this.state.a}</p>
<button
onClick={() => {
this.setState({ a: 1 }); // 這里并沒有改變 a 的值
}}
\>
Click me
</button>
<button onClick={() => this.setState(null)}>setState null</button>
<Child />
</React.Fragement>
);
}
}
- 父組件重新渲染
只要父組件重新渲染了霉旗,即使傳入子組件的 props 未發(fā)生變化,那么子組件也會重新渲染,進而觸發(fā) render
(2)重新渲染 render 會做些什么?
- 會對新舊 VNode 進行對比厌秒,也就是我們所說的Diff算法读拆。
- 對新舊兩棵樹進行一個深度優(yōu)先遍歷,這樣每一個節(jié)點都會一個標記鸵闪,在到深度遍歷的時候檐晕,每遍歷到一和個節(jié)點,就把該節(jié)點和新的節(jié)點樹進行對比蚌讼,如果有差異就放到一個對象里面
- 遍歷差異對象辟灰,根據(jù)差異的類型,根據(jù)對應(yīng)對規(guī)則更新VNode
React 的處理 render 的基本思維模式是每次一有變動就會去重新渲染整個應(yīng)用啦逆。在 Virtual DOM 沒有出現(xiàn)之前伞矩,最簡單的方法就是直接調(diào)用 innerHTML。Virtual DOM厲害的地方并不是說它比直接操作 DOM 快夏志,而是說不管數(shù)據(jù)怎么變乃坤,都會盡量以最小的代價去更新 DOM。React 將 render 函數(shù)返回的虛擬 DOM 樹與老的進行比較沟蔑,從而確定 DOM 要不要更新湿诊、怎么更新。當 DOM 樹很大時瘦材,遍歷兩棵樹進行各種比對還是相當耗性能的厅须,特別是在頂層 setState 一個微小的修改,默認會去遍歷整棵樹食棕。盡管 React 使用高度優(yōu)化的 Diff 算法朗和,但是這個過程仍然會損耗性能.
React如何判斷什么時候重新渲染組件?
組件狀態(tài)的改變可以因為props
的改變簿晓,或者直接通過setState
方法改變眶拉。組件獲得新的狀態(tài),然后React決定是否應(yīng)該重新渲染組件憔儿。只要組件的state發(fā)生變化忆植,React就會對組件進行重新渲染。這是因為React中的shouldComponentUpdate
方法默認返回true
谒臼,這就是導致每次更新都重新渲染的原因朝刊。
當React將要渲染組件時會執(zhí)行shouldComponentUpdate
方法來看它是否返回true
(組件應(yīng)該更新,也就是重新渲染)蜈缤。所以需要重寫shouldComponentUpdate
方法讓它根據(jù)情況返回true
或者false
來告訴React什么時候重新渲染什么時候跳過重新渲染拾氓。
React****聲明組件有哪幾種方法,有什么不同劫樟?
React 聲明組件的三種方式:
- 函數(shù)式定義的無狀態(tài)組件
- ES5原生方式React.createClass定義的組件
- ES6形式的extends React.Component定義的組件
(1)無狀態(tài)函數(shù)式組件 它是為了創(chuàng)建純展示組件痪枫,這種組件只負責根據(jù)傳入的props來展示织堂,不涉及到state狀態(tài)的操作 組件不會被實例化,整體渲染性能得到提升奶陈,不能訪問this對象易阳,不能訪問生命周期的方法
(2)ES5 原生方式 React.createClass // RFC React.createClass會自綁定函數(shù)方法,導致不必要的性能開銷吃粒,增加代碼過時的可能性潦俺。
(3)E6繼承形式 React.Component // RCC 目前極為推薦的創(chuàng)建有狀態(tài)組件的方式,最終會取代React.createClass形式徐勃;相對于 React.createClass可以更好實現(xiàn)代碼復用事示。
無狀態(tài)組件相對于于后者的區(qū)別: 與無狀態(tài)組件相比,React.createClass和React.Component都是創(chuàng)建有狀態(tài)的組件僻肖,這些組件是要被實例化的肖爵,并且可以訪問組件的生命周期方法。
React.createClass****與React.Component區(qū)別:
① 函數(shù)this自綁定
- React.createClass創(chuàng)建的組件臀脏,其每一個成員函數(shù)的this都有React自動綁定劝堪,函數(shù)中的this會被正確設(shè)置。
- React.Component創(chuàng)建的組件揉稚,其成員函數(shù)不會自動綁定this秒啦,需要開發(fā)者手動綁定,否則this不能獲取當前組件實例對象搀玖。
② 組件屬性類型propTypes及其默認props屬性defaultProps配置不同
- React.createClass在創(chuàng)建組件時余境,有關(guān)組件props的屬性類型及組件默認的屬性會作為組件實例的屬性來配置,其中defaultProps是使用getDefaultProps的方法來獲取默認組件屬性的
- React.Component在創(chuàng)建組件時配置這兩個對應(yīng)信息時灌诅,他們是作為組件類的屬性芳来,不是組件實例的屬性,也就是所謂的類的靜態(tài)屬性來配置的猜拾。
③ 組件初始狀態(tài)state的配置不同
- React.createClass創(chuàng)建的組件绣张,其狀態(tài)state是通過getInitialState方法來配置組件相關(guān)的狀態(tài);
- React.Component創(chuàng)建的組件关带,其狀態(tài)state是在constructor中像初始化組件屬性一樣聲明的。
對React中Fragment的理解沼撕,它的使用場景是什么宋雏?
在React中,組件返回的元素只能有一個根元素务豺。為了不添加多余的DOM節(jié)點磨总,我們可以使用Fragment標簽來包裹所有的元素,F(xiàn)ragment標簽不會渲染出任何元素笼沥。React官方對Fragment的解釋:
React 中的一個常見模式是一個組件返回多個元素蚪燕。Fragments 允許你將子列表分組娶牌,而無需向 DOM 添加額外節(jié)點。
import React, { Component, Fragment } from 'react'
// 一般形式
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
// 也可以寫成以下形式
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
在React中如何避免不必要的render馆纳?
React 基于虛擬 DOM 和高效 Diff 算法的完美配合诗良,實現(xiàn)了對 DOM 最小粒度的更新。大多數(shù)情況下鲁驶,React 對 DOM 的渲染效率足以業(yè)務(wù)日常鉴裹。但在個別復雜業(yè)務(wù)場景下,性能問題依然會困擾我們钥弯。此時需要采取一些措施來提升運行性能径荔,其很重要的一個方向,就是避免不必要的渲染(Render)脆霎。這里提下優(yōu)化的點:
- shouldComponentUpdate 和 PureComponent
在 React 類組件中总处,可以利用 shouldComponentUpdate或者 PureComponent 來減少因父組件更新而觸發(fā)子組件的 render,從而達到目的睛蛛。shouldComponentUpdate 來決定是否組件是否重新渲染鹦马,如果不希望組件重新渲染,返回 false 即可玖院。
- 利用高階組件
在函數(shù)組件中菠红,并沒有 shouldComponentUpdate 這個生命周期,可以利用高階組件难菌,封裝一個類似 PureComponet 的功能
- 使用 React.memo
React.memo 是 React 16.6 新的一個 API试溯,用來緩存組件的渲染,避免不必要的更新郊酒,其實也是一個高階組件遇绞,與 PureComponent 十分類似,但不同的是燎窘, React.memo只能用于函數(shù)組件摹闽。
setState 是同步還是異步的
假如所有setState是同步的,意味著每執(zhí)行一次setState時(有可能一個同步代碼中褐健,多次setState)付鹿,都重新vnode diff + dom修改,這對性能來說是極為不好的蚜迅。如果是異步舵匾,則可以把一個同步代碼中的多個setState合并成一次組件更新。所以默認是異步的谁不,但是在一些情況下是同步的坐梯。
setState 并不是單純同步/異步的,它的表現(xiàn)會因調(diào)用場景的不同而不同刹帕。在源碼中吵血,通過 isBatchingUpdates 來判斷setState 是先存進 state 隊列還是直接更新谎替,如果值為 true 則執(zhí)行異步操作,為 false 則直接更新蹋辅。
- 異步: 在 React 可以控制的地方钱贯,就為 true,比如在 React 生命周期事件和合成事件中晕翠,都會走合并操作喷舀,延遲更新的策略。
- 同步: 在 React 無法控制的地方淋肾,比如原生事件硫麻,具體就是在 addEventListener 、setTimeout樊卓、setInterval 等事件中拿愧,就只能同步更新。
一般認為碌尔,做異步設(shè)計是為了性能優(yōu)化浇辜、減少渲染次數(shù):
- setState設(shè)計為異步,可以顯著的提升性能唾戚。如果每次調(diào)用 setState都進行一次更新柳洋,那么意味著render函數(shù)會被頻繁調(diào)用,界面重新渲染叹坦,這樣效率是很低的熊镣;最好的辦法應(yīng)該是獲取到多個更新,之后進行批量更新募书;
- 如果同步更新了state绪囱,但是還沒有執(zhí)行render函數(shù),那么state和props不能保持同步莹捡。state和props不能保持一致性鬼吵,會在開發(fā)中產(chǎn)生很多的問題;
React的狀態(tài)提升是什么篮赢?使用場景有哪些齿椅?
React的狀態(tài)提升就是用戶對子組件操作,子組件不改變自己的狀態(tài)启泣,通過自己的props把這個操作改變的數(shù)據(jù)傳遞給父組件媒咳,改變父組件的狀態(tài),從而改變受父組件控制的所有子組件的狀態(tài)种远,這也是React單項數(shù)據(jù)流的特性決定的。官方的原話是:共享 state(狀態(tài)) 是通過將其移動到需要它的組件的最接近的共同祖先組件來實現(xiàn)的顽耳。 這被稱為“狀態(tài)提升(Lifting State Up)”坠敷。
概括來說就是將多個組件需要共享的狀態(tài)提升到它們最近的父組件上妙同,在父組件上改變這個狀態(tài)然后通過props分發(fā)給子組件。
生成指定長度的隨機字母數(shù)字字符串
function getRandomStr(len) {
var str = ""
for (var i = 0; i < len; i++ ) {
str += Math.random().toString(36).substring(2)
}
return str.substring(0, len)
}
1. 網(wǎng)絡(luò)模式
OSI七層
應(yīng)用層
表示層
會話層
傳輸層
網(wǎng)絡(luò)層
數(shù)據(jù)鏈路層
物理層
TCP/IP五層
應(yīng)用層
傳輸層
網(wǎng)絡(luò)層
數(shù)據(jù)鏈路層
物理層
2. 強制緩存與協(xié)商緩存
強制緩存不會向服務(wù)器發(fā)送請求膝迎,直接在緩存資源中讀取粥帚,返回狀態(tài)嗎200
協(xié)商緩存會向服務(wù)器發(fā)送請求,服務(wù)器會根據(jù)請求頭的參數(shù)來判斷是否命中協(xié)商緩存限次,如果命中則返回304芒涡,并帶上新的response header通知瀏覽器從緩存中讀取資源
強制緩存:
Expires:response header里的過期時間,瀏覽器再次加載資源時卖漫,如果在這個過期時間內(nèi)费尽,則命中強緩存。
Cache-Control****:當值設(shè)為max-age=300時羊始,則代表在這個請求正確返回時間(瀏覽器也會記錄下來)的5分鐘內(nèi)再次加載資源旱幼,就會命中強緩存。
cache-control****除了該字段外突委,還有下面幾個比較常用的設(shè)置值:
-no-cache****:不使用本地緩存柏卤。需要使用緩存協(xié)商,先與服務(wù)器確認返回的響應(yīng)是否被更改匀油,如果之前的響應(yīng)中存在ETag缘缚,那么請求的時候會與服務(wù)端驗證,如果資源未被更改敌蚜,則可以避免重新下載桥滨。
-no-store****:直接禁止瀏覽器緩存數(shù)據(jù),每次用戶請求該資源钝侠,都會向服務(wù)器發(fā)送一個請求该园,每次都會下載完整的資源。
-public****:可以被所有的用戶緩存帅韧,包括終端用戶和CDN等中間代理服務(wù)器里初。
-private****:只能被終端用戶的瀏覽器緩存,不允許CDN等中繼緩存服務(wù)器對其緩存忽舟。
協(xié)商緩存
Last-Modify/If-Modify-Since:瀏覽器第一次請求一個資源的時候双妨,服務(wù)器返回的header中會加上Last-Modify,Last-modify是一個時間標識該資源的最后修改時間叮阅;當瀏覽器再次請求該資源時刁品,request的請求頭中會包含If-Modify-Since,該值為緩存之前返回的Last-Modify浩姥。服務(wù)器收到If-Modify-Since后挑随,根據(jù)資源的最后修改時間判斷是否命中緩存
Etag****:web服務(wù)器響應(yīng)請求時,告訴瀏覽器當前資源在服務(wù)器的唯一標識(生成規(guī)則由服務(wù)器決定)勒叠。
If-None-Match****:當資源過期時(使用Cache-Control標識的max-age)兜挨,發(fā)現(xiàn)資源具有Etage聲明膏孟,則再次向web服務(wù)器請求時帶上頭If-None-Match (Etag的值)。web服務(wù)器收到請求后發(fā)現(xiàn)有頭If-None-Match 則與被請求資源的相應(yīng)校驗串進行比對拌汇,決定是否命中協(xié)商緩存柒桑;
ETag****和Last-Modified的作用和用法,他們的區(qū)別:
1.Etag要優(yōu)于Last-Modified噪舀。Last-Modified的時間單位是秒魁淳,如果某個文件在1秒內(nèi)改變了多次,那么他們的Last-Modified其實并沒有體現(xiàn)出來修改与倡,但是Etag每次都會改變確保了精度界逛;
2.在性能上,Etag要遜于Last-Modified蒸走,畢竟Last-Modified只需要記錄時間仇奶,而Etag需要服務(wù)器通過算法來計算出一個hash值;
3.在優(yōu)先級上比驻,服務(wù)器校驗優(yōu)先考慮Etag该溯。
瀏覽器緩存過程
1.瀏覽器第一次加載資源,服務(wù)器返回200别惦,瀏覽器將資源文件從服務(wù)器上請求下載下來狈茉,并把response header及該請求的返回時間一并緩存;
2.下一次加載資源時掸掸,先比較當前時間和上一次返回200時的時間差氯庆,如果沒有超過cache-control設(shè)置的max-age,則沒有過期扰付,命中強緩存堤撵,不發(fā)請求直接從本地緩存讀取該文件(如果瀏覽器不支持HTTP1.1,則用expires判斷是否過期)羽莺;如果時間過期实昨,則向服務(wù)器發(fā)送header帶有If-None-Match和If-Modified-Since的請求
3.服務(wù)器收到請求后,優(yōu)先根據(jù)Etag的值判斷被請求的文件有沒有做修改盐固,Etag值一致則沒有修改荒给,命中協(xié)商緩存,返回304刁卜;如果不一致則有改動志电,直接返回新的資源文件帶上新的Etag值并返回200;蛔趴;
4.如果服務(wù)器收到的請求沒有Etag值挑辆,則將If-Modified-Since和被請求文件的最后修改時間做比對,一致則命中協(xié)商緩存,返回304之拨;不一致則返回新的last-modified和文件并返回200茉继;;