JS所有的操作都是通過(guò)Native端的js線(xiàn)程執(zhí)行,單線(xiàn)程執(zhí)行,優(yōu)化性能的一個(gè)方向就是降低js的負(fù)載。
Imutualble概念:顧名思義,對(duì)象一旦被創(chuàng)建便不能更改,對(duì)immutable對(duì)象的修改添加刪除都會(huì)返回一個(gè)新的immutable對(duì)象,同時(shí)為了避免deepCopy的性能損耗,immutable引入了Structural Sharing(結(jié)構(gòu)共享),如果對(duì)象只是一個(gè)節(jié)點(diǎn)發(fā)生變化,只修改這個(gè)節(jié)點(diǎn)和受它影響的父節(jié)點(diǎn),其他節(jié)點(diǎn)共享。官方地址:https://facebook.github.io/immutable-js/
Immutable優(yōu)點(diǎn):
(1)降低了Mutual帶來(lái)的復(fù)雜度
(2)節(jié)省內(nèi)存
(3)Undo/Redo,Copy/Paste,甚至?xí)r間旅行這些功能做起來(lái)小菜一碟
(4)并發(fā)安全
(5)擁抱函數(shù)式編程
應(yīng)用:
(1)shouldComponentUpdate()中的deepCompare
熟悉 React 的都知道,React 做性能優(yōu)化時(shí)有一個(gè)避免重復(fù)渲染的大招,就是使用 shouldComponentUpdate(),但它默認(rèn)返回 true,即始終會(huì)執(zhí)行 render() 方法,然后做 Virtual DOM 比較,并得出是否需要做真實(shí) DOM 更新,這里往往會(huì)帶來(lái)很多無(wú)必要的渲染并成為性能瓶頸。
react的組件渲染分為初始化渲染和更新渲染。在初始化渲染的時(shí)候會(huì)調(diào)用根組件下的所有組件的render方法進(jìn)行渲染,如下圖(綠色表示已渲染,這一層是沒(méi)有問(wèn)題的):

但是當(dāng)我們要更新某個(gè)子組件的時(shí)候,如下圖的綠色組件(從根組件傳遞下來(lái)應(yīng)用在綠色組件上的數(shù)據(jù)發(fā)生改變,Redux通過(guò)Provider傳遞給子組件):
我們的理想狀態(tài)是只調(diào)用關(guān)鍵路徑上組件的render,如下圖:
但是react的默認(rèn)做法是調(diào)用所有組件的render,再對(duì)生成的虛擬DOM進(jìn)行對(duì)比,如不變則不進(jìn)行更新。這樣的render和虛擬DOM的對(duì)比明顯是在浪費(fèi),如下圖(黃色表示浪費(fèi)的render和虛擬DOM對(duì)比)
Tips:
拆分組件是有利于復(fù)用和組件優(yōu)化的。
父組件如果返回false,則不對(duì)子組件生成新的虛擬DOM進(jìn)行對(duì)比。
所以:寫(xiě)好每個(gè)組件的shouldComponentUpdate()方法,可以避免子組件DOM的生成以及對(duì)比。
我們可以實(shí)現(xiàn)一個(gè)baseCommponent類(lèi),實(shí)現(xiàn)shouldComponentUpdate():
export default class BaseComponent extends Component {
shouldComponentUpdate(nextProps, nextState) {
if (!Immutable.is(thisProps, nextProps) || !Immutable.is(thisState, nextState)) {
return true;
}
return false;
}
}
所有的組件不在繼承Commponent,而是繼承這個(gè)baseCommponent;
(2)reducer中的deepCopy
immutable深拷貝時(shí)有性能優(yōu)勢(shì),reducer中對(duì)舊數(shù)據(jù)的深拷貝我們可以這樣寫(xiě):
export default function DLTHistoryList(state = defaultUserState, action) {
switch (action.type) {
case types.DLTHISTORYLIST_REFRESHLIST:
return state.merge(Immutable.fromJS({
isRefreshing: false,
historyItems: action.payload.latestTwentyItems,
hasNextPage: action.payload.latestTwentyItems.length >= 20,
isEmpty: action.payload.latestTwentyItems.length <= 0,
awardRankArray: action.payload.awardRankArray,
}));
default:
return state;
}
}
注意:
由于 Redux 中內(nèi)置的 combineReducers 和 reducer 中的 initialState 都為原生的 Object 對(duì)象,所以不能和 Immutable 原生搭配使用。幸運(yùn)的是,Redux 并不排斥使用 Immutable,可以自己重寫(xiě) combineReducers或使用 redux-immutablejs 來(lái)提供支持。
使用很簡(jiǎn)單:
將 import { combineReducers } from 'redux'; 替換為 import { combineReducers } from 'redux-immutable';
總結(jié)
Immutable 可以給應(yīng)用帶來(lái)極大的性能提升,但是否使用還要看項(xiàng)目情況。由于侵入性較強(qiáng),新項(xiàng)目引入比較容易,老項(xiàng)目遷移需要評(píng)估遷移。對(duì)于一些提供給外部使用的公共組件,最好不要把 Immutable 對(duì)象直接暴露在對(duì)外接口中。
參考
https://github.com/Pines-Cheng/blog/issues/3
https://github.com/camsong/blog/issues/3