React优化-记忆化技术-使用闭包提升你的React性能
为什么要使用记忆性技术?
使用React开发的时候,我们请求服务器拿回来一个复杂的数据,我们在render里去处理这个数据,但是state和props频繁修改会触发render,每次触发render,数据都要去处理一次,每次处理都是对性能的损耗
举个例子:把大于18岁的人列出来
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,每次处理都是对性能的损耗!
什么叫记忆性技术?
每次调用函数把你的传参和结果记录下来,遇到相同的传参,就直接返回记录缓存的结果,不用再去调用函数处理数据!
memoize-one官方案例
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 函数再次被调用,返回一个新的结果
我们可以发现连续两次相同传参,第二次会直接返回上次的结果,每次传参不一样,就直接调用函数返回新的结果,会丢失之前的记录,并不是完全记忆,这也是个不足点!
在React中使用memoize-one
根据上的例子,我们对那个例子进行修改,使用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源码解析
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);
}
关于isEqual函数(memoize-one推荐使用loadsh.isEqual)
一般两个对象比较是否相等,我们不能用===或者==来处理,memoize-one允许用户自定义传入判断是否相等的函数,比如我们可以使用lodash的isEqual来判断两次参数是否相等
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判断是相等的
参考
推荐阅读
React-新的生命周期(React16版本)
组件生命周期的三个阶段Mounting(加载阶段)Updating(更新阶段)Unmounting(卸载阶段)旧的生命周期Mounting(加载阶段:涉及6个钩子函数)constructor() {代码...} getDefaultProps() {代码...} getInitialSt...
Nine赞 135阅读 67.6k评论 5
JavaScript有用的代码片段和trick
平时工作过程中可以用到的实用代码集棉。判断对象否为空 {代码...} 浮点数取整 {代码...} 注意:前三种方法只适用于32个位整数,对于负数的处理上和Math.floor是不同的。 {代码...} 生成6位数字验证码 {代码...} ...
jenemy赞 46阅读 5.9k评论 12
从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...
乌柏木赞 66阅读 6.1k评论 16
再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...
libinfs赞 39阅读 6.3k评论 12
从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...
乌柏木赞 43阅读 7.3k评论 6
CSS 绘制一只思否猫
欢迎关注我的公众号:前端侦探练习 CSS 有一个比较有趣的方式,就是发挥想象,绘制各式各样的图案,比如来绘制一只思否猫?思否猫,SegmentFault 思否的吉祥物,是一只独一无二、特立独行、热爱自由的(>^ω^<...
XboxYan赞 43阅读 2.9k评论 14
从零搭建 Node.js 企业级 Web 服务器(二):校验
校验就是对输入条件的约束,避免无效的输入引起异常。Web 系统的用户输入主要为编辑与提交各类表单,一方面校验要做在编辑表单字段与提交的时候,另一方面接收表单的接口也要做足校验行为,通过前后端共同控制输...
乌柏木赞 33阅读 6.2k评论 9
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。