學習筆記——immutable
為什麼有immutable
JavaScript 中的物件一般是可變的(Mutable),因為使用了引用賦值,新的物件簡單的引用了原始物件,改變新的物件將影響到原始物件。
當應用複雜後,這樣會造成很大隱患,於是有了深拷貝,淺拷貝。但是這些操作會造成CPU和記憶體的浪費,於是就有了immutable。
什麼是immutable資料?
Immutable Data 就是一旦建立,就不能再被更改的資料。對 Immutable 物件的任何修改或新增刪除操作都會返回一個新的 Immutable 物件。
Immutable 實現的原理是 Persistent Data Structure(持久化資料結構),也就是使用舊資料建立新資料時,要保證舊資料同時可用且不變。同時為了避免 deepCopy 把所有節點都複製一遍帶來的效能損耗,Immutable 使用了 Structural Sharing(結構共享),即如果物件樹中一個節點發生變化,只修改這個節點和受它影響的父節點,其它節點則進行共享。
immutable的優點
1.降低了mutable帶來的複雜度。可變資料耦合了time和Value的概念,造成資料很難被回溯。
2.節省記憶體。immutable.js使用了結構共享來儘可能地複用記憶體,甚至以前使用的物件也可以再次被複用。沒有被引用的物件會被垃圾回收。
import { Map} from 'immutable'; let a = Map({ select: 'users', filter: Map({ name: 'Cam' }) }) let b = a.set('select', 'people'); a === b; // false a.get('filter') === b.get('filter'); // true
上面 a 和 b 共享了沒有變化的 filter
節點。
3.想回退到哪裡就拿出對應資料即可,很容易開發出撤銷重做這種功能。
4.併發安全。使用了 Immutable 之後,資料天生是不可變的,併發鎖就不需要了。
5.函數語言程式設計。純函數語言程式設計比物件導向更適用於前端開發。因為只要輸入一致,輸出必然一致,這樣開發的元件更易於除錯和組裝。
immutable的缺點:
1.需要學習新的API
2.增加了資原始檔大小
3.容易與原生物件混淆
更多認識
immutable.is
2個immutable物件可以使用===進行比較,這樣是直接比較記憶體地址。但即使兩個物件的值是一樣的,也返回false。
let map1 = Immutable.Map({a:1, b:1, c:1});
let map2 = Immutable.Map({a:1, b:1, c:1});
map1 === map2; //false
為了直接比較物件的值,immutable.js 提供了 Immutable.is
來做『值比較』,結果如下:
Immutable.is(map1, map2); // true
Immutable.is
比較的是兩個物件的 hashCode
或 valueOf
(對於 JavaScript 物件)。由於 immutable 內部使用了 Trie 資料結構來儲存,只要兩個物件的 hashCode
相等,值就是一樣的。這樣的演算法避免了深度遍歷比較,效能非常好。
cursor
由於 Immutable 資料一般巢狀非常深,為了便於訪問深層資料,Cursor 提供了可以直接訪問這個深層資料的引用。
import Immutable from 'immutable';
import Cursor from 'immutable/contrib/cursor';
let data = Immutable.fromJS({ a: { b: { c: 1 } } });
// 讓 cursor 指向 { c: 1 }
let cursor = Cursor.from(data, ['a', 'b'], newData => {
// 當 cursor 或其子 cursor 執行 update 時呼叫
console.log(newData);
});
cursor.get('c'); // 1
cursor = cursor.update('c', x => x + 1);
cursor.get('c'); // 2
實踐
React 做效能優化時有一個避免重複渲染的大招,就是使用 shouldComponentUpdate()
,但它預設返回 true
,即始終會執行 render()
方法,然後做 Virtual DOM 比較,並得出是否需要做真實 DOM 更新,這裡往往會帶來很多無必要的渲染併成為效能瓶頸。
我們也可以在 shouldComponentUpdate()
中使用使用 deepCopy 和 deepCompare 來避免無必要的 render()
,但 deepCopy 和 deepCompare 一般都是非常耗效能的。
Immutable 則提供了簡潔高效的判斷資料是否變化的方法,只需 ===
和 is
比較就能知道是否需要執行 render()
,而這個操作幾乎 0 成本,所以可以極大提高效能。修改後的 shouldComponentUpdate
是這樣的:
import { is } from 'immutable';
shouldComponentUpdate: (nextProps = {}, nextState = {}) => {
const thisProps = this.props || {}, thisState = this.state || {};
if (Object.keys(thisProps).length !== Object.keys(nextProps).length ||
Object.keys(thisState).length !== Object.keys(nextState).length) {
return true;
}
for (const key in nextProps) {
if (!is(thisProps[key], nextProps[key])) {
return true;
}
}
for (const key in nextState) {
if (thisState[key] !== nextState[key] && !is(thisState[key], nextState[key])) {
return true;
}
}
return false;
}
相關文章
- numpy的學習筆記\pandas學習筆記筆記
- 學習筆記筆記
- 【學習筆記】數學筆記
- 機器學習學習筆記機器學習筆記
- 《JAVA學習指南》學習筆記Java筆記
- 學習筆記-粉筆980筆記
- fastadmin學習筆記AST筆記
- JAVA學習筆記Java筆記
- FFT學習筆記FFT筆記
- HTML學習筆記HTML筆記
- wireshark學習筆記筆記
- LCA學習筆記筆記
- Tarjan 學習筆記筆記
- TensorFlow 學習筆記筆記
- PyTorch 學習筆記PyTorch筆記
- 字串學習筆記字串筆記
- Go 學習筆記Go筆記
- Bash 學習筆記筆記
- argparse學習筆記筆記
- Rust 學習筆記Rust筆記
- Python學習筆記Python筆記
- SpringBoot學習筆記Spring Boot筆記
- 吉他學習筆記筆記
- PHP 學習筆記PHP筆記
- Docker學習筆記Docker筆記
- AJAX學習筆記筆記
- TVM學習筆記筆記
- Flask學習筆記Flask筆記
- 2024.3.6學習筆記筆記
- Mockito 學習筆記Mockito筆記
- Docker 學習筆記Docker筆記
- Dart 學習筆記Dart筆記
- SpringMVC學習筆記SpringMVC筆記
- Reverse學習筆記筆記
- Crypto學習筆記筆記
- DSP學習筆記筆記
- SQL學習筆記SQL筆記
- VINS學習筆記筆記