咱们写后端代码的时候, 为了在密集查询时候尽可能少的去操做数据库, 一个方法就是在中间插入一个缓存层,当查询的数据能够在缓存中查询到时候就直接用缓存里面的数据,若是数据改变了再去修改缓存里面的数据。javascript
随着前端近些年的飞速发展,前端项目(特别在spa)应用中,前端须要储存愈来愈多的数据内容,就像一个小型的数据库。前端
对前端而言这些数据咱们都是直接存在内存中的, 因此查询对咱们来讲并非什么难事, 可是页面上要展现的内容每每是须要基础数据通过复杂计算获得的结果,每次从新计算都会消耗大量的性能。一种方法是咱们去创建一些存贮结果变量, 每次原始值发生改变时候咱们再去从新计算而后从新赋值。可是咱们又要去维护这些新的变量,在代码维护和后期功能迭代时候有可能会给咱们带来很大的困扰。可是每次都重新计算却会大量消耗咱们计算机的性能。java
有作过这样一个题目,斐波那契数列指的是相似于如下的数列:1, 1, 2, 3, 5, 8, 13, ....
,也就是第 n
个数由数列的前两个相加而来:f(n) = f(n - 1) + f(n -2)
, 请你完成 fibonacci
函数,接受 n
做为参数,能够获取数列中第 n
个数。测试程序会从按顺序依次获取斐波那契数列中的数,请注意程序不要超时,也不要添加额外的全局变量。react
这个题目比较经典也很好理解, 我当时简单的想到一个实现git
const fibonacci = n =>{ let [a, b] = [0, 1] while(n--){[a, b] = [b, a + b]} return a }
看起来彷佛没什么问题,可是当我提交答案时候老是提示超时。当时去网上搜索发现还有用 数学公式和二分矩阵方法
计算的,当时觉得题目是在考察这些还感受考察的有些偏。后面仔细看看了题目,上面说测试程序会依次获取数列中的数。忽然想到我这个方法每一次执行其实都是要从头开始计算一次,可是后面的数其实就是前两次计算结果的和。有没有什么办法能够把前面计算的数存储起来呢。后面想到这样一种实现。github
const fibonacci = ((memory = {}) => n => { if(n < 2) return n if(memory[n-2] === undefined){ memory[n-2] = fibonacci(n-2) } if(memory[n-1] === undefined){ memory[n-1] = fibonacci(n-1) } return memory[n] = memory[n-1] + memory[n-2] })()
这里咱们用 iife
返回了一个函数。可是它每次执行都会把值存在内部的 memory
变量里,咱们下次计算新的值这些已经计算过的值就不用子再去计算了。这样就大大节省了计算量。算法
咱们用 react
构建平常应用时候, 一般会用 redux
来存储数据。咱们页面上大部分展现都和 redux
中的数据有关,其中一部分是须要通过复杂的计算而后在进行展现。咱们知道改变组件的state
或者组件里用到的 redux
里面的值都会从新渲染咱们的咱们的组件。若是咱们页面里的值是通过复杂计算的获得的,每次从新渲染都会消耗大量的性能。能不能每次计算后都把结果缓存起来只有当计算条件发生改变了咱们再从新计算呢。 reselect
能够帮助咱们去实现这个功能。数据库
Reselect
提供的了个 createSelector
函数, 它能够帮助咱们建立一个 记忆化的选择器
, createSelector
第一个参数是由数据选择器函数组成的数组做,而后最后一个参数为数据转换器函数它的参数正是前面这些选择器选择到的值。简单的看以下npm
import { createSelector } from 'reselect' store = { a: 1, b: 2 } const getA = store => store.a const getB = store => store.b const getSum = createSelector( [getA, getB], (a, b) => a + b ) getSum(store) // 3
能够看到最后的数据转换函数,它接受的参数就是前面这些数据选择函数选择到的内容,固然这些函数接收到的参数都是最后咱们执行 getSum
函数时候传入的参数, 有 getSum
生产的函数就会具备记忆
功能,只有当选择器函数的结果发生改变时候,它才会去执行最后的数据转换函数,不然则直接返回以前计算过的值。redux
假设咱们有一组选择框,上面分别罗列了各个商品的名称和价钱,咱们须要在底部展现咱们当前选择商品的价格总和。这里咱们用 redux
实现。
咱们在 state
中放置一个商品数组。相似list = [{name: 'item1', price: 12, checked: false},...]
,这里咱们直接用 checked
属性控制商品是否被选中。而后用两种方法去计算当前选中项的价格总和
// input-selectors const getList = state => state.home.list /** * create select by reselect * @type {object} state */ const getTotal1 = createSelector( getList, items => { console.log('getTotal1 将要计算') return items.reduce((acc, item) => acc + (item.checked ? item.price : 0), 0) } ) /** * create select smiple * @param {array} items * @return {number} total checked value */ const getTotal2 = items => { console.log('getTotal2 将要计算') return items.reduce((acc, item) => acc + (item.checked ? item.price : 0), 0) }
咱们经过 reselect
建立一个记忆化函数 getTotal1
。而后本身在简单的写一个计算总和的函数 getTotal2
。咱们在页面里加入一个 input
输入框它的值页关联到 redux
的 state
中。咱们能够看到当 getTotal1
和 getTotal2
执行计算时候分别会 log
出相对应的信息。测试实际效果发现
当咱们改变 list
里面对值时候两个计算都会发生,可是当咱们改变无关变量 input
的值时候,reselect
创造的选择计算器内部的计算就不会发生,这是由于它的数据源对应的列表并无发生过变化。这样就节省了很大的计算量。
实例在项目 react-ggsddu
运行 npm run reselect
体验。
reselect
还有不少其余的 api
以及使用场景,在他的 文档 里面已经说的很清楚了。
感受有时候看有些题目已经算法之类的总感受这些都是纯粹为了作题,可是后面本身发现不少思想和技巧其实都在这里面。
every thing think twice