使用React开发的时候,咱们请求服务器拿回来一个复杂的数据,咱们在render里去处理这个数据,可是state和props频繁修改会触发render,每次触发render,数据都要去处理一次,每次处理都是对性能的损耗javascript
举个例子:把大于18岁的人列出来java
class Example extends Component { ... render() { const { dataList } = this.props; const newDataList = dataList.filter((item) => item.age > 18); return ( <div> {newDataList.map((item, i) => <p key={i}>{item.name}:{item.age}岁</p> )} </div> ) } ... }
从例子中咱们看到render中咱们处理数据,可是每次state和props的修改都会触发render,都会去处理数据dataList,生成新的数据newDataList,每次处理都是对性能的损耗!git
每次调用函数把你的传参和结果记录下来,遇到相同的传参,就直接返回记录缓存的结果,不用再去调用函数处理数据!github
import memoizeOne from 'memoize-one'; const add = (a, b) => a + b; const memoizedAdd = memoizeOne(add); memoizedAdd(1, 2); // 3 memoizedAdd(1, 2); // 3 // Add 函数并无执行: 前一次执行的结果被返回 memoizedAdd(2, 3); // 5 // Add 函数再次被调用,返回一个新的结果 memoizedAdd(2, 3); // 5 // Add 函数并无执行: 前一次执行的结果被返回 memoizedAdd(1, 2); // 3 // Add 函数再次被调用,返回一个新的结果
咱们能够发现连续两次相同传参,第二次会直接返回上次的结果,每次传参不同,就直接调用函数返回新的结果,会丢失以前的记录,并非彻底记忆,这也是个不足点!缓存
根据上的例子,咱们对那个例子进行修改,使用memoize-one提高React的性能服务器
import memoize from "memoize-one"; class Example extends Component { ... filter = memoize((dataList, age) => dataList.filter((item) => item.age > age)) render() { const { dataList } = this.props; const newDataList = this.filter(dataList, 18) return ( <div> ... {newDataList.map((item, i) => <p key={i}>{item.name}:{item.age}岁</p> )} ... </div> ) } ... }
memoize-one是采用闭包来缓存数据的闭包
type EqualityFn = (a: mixed, b: mixed) => boolean; const simpleIsEqual: EqualityFn = (a: mixed, b: mixed): boolean => a === b; export default function <ResultFn: (...Array<any>) => mixed>(resultFn: ResultFn, isEqual?: EqualityFn = simpleIsEqual): ResultFn { let lastThis: mixed; // 用来缓存上一次result函数对象 let lastArgs: Array<mixed> = []; // 用来缓存上一次的传参 let lastResult: mixed; // 用来缓存上一次的结果 let calledOnce: boolean = false; // 是否以前调用过 // 判断两次调用的时候的参数是否相等 // 这里的 `isEqual` 是一个抽象函数,用来判断两个值是否相等 const isNewArgEqualToLast = (newArg: mixed, index: number): boolean => isEqual(newArg, lastArgs[index]); const result = function (...newArgs: Array<mixed>) { if (calledOnce && lastThis === this && newArgs.length === lastArgs.length && newArgs.every(isNewArgEqualToLast)) { // 返回以前的结果 return lastResult; } calledOnce = true; // 标记已经调用过 lastThis = this; // 从新缓存result对象 lastArgs = newArgs; // 从新缓存参数 lastResult = resultFn.apply(this, newArgs); // 从新缓存结果 return lastResult; // 返回新的结果 }; // 返回闭包函数 return (result: any); }
通常两个对象比较是否相等,咱们不能用===或者==来处理,memoize-one容许用户自定义传入判断是否相等的函数,好比咱们可使用lodash的isEqual来判断两次参数是否相等app
import memoizeOne from 'memoize-one'; import deepEqual from 'lodash.isEqual'; const identity = x => x; const defaultMemoization = memoizeOne(identity); const customMemoization = memoizeOne(identity, deepEqual); const result1 = defaultMemoization({foo: 'bar'}); const result2 = defaultMemoization({foo: 'bar'}); result1 === result2 // false - 索引不一样 const result3 = customMemoization({foo: 'bar'}); const result4 = customMemoization({foo: 'bar'}); result3 === result4 // true - 参数经过lodash.isEqual判断是相等的