美文网首页
memoization的简介和应用

memoization的简介和应用

作者: 灰色的龙猫 | 来源:发表于2019-07-30 10:42 被阅读0次

    定义

    利用缓存方式减少昂贵计算所带来的性能耗费,常用语递归或频繁计算当中

    举例

    
    // 获取函数运行时间
    function getTime(fn, ...args) {
      const now = Date.now()
      const result = fn.apply(null, args)
      console.log(`用时:${Date.now() -  now}毫秒,结果:${result}`)
    }
    
    // 斐波那契数列
    function fibonacci (n) {
      if (n === 0) return 0
      else if (n === 1) return 1
      else return fibonacci(n - 1) + fibonacci(n - 2)
    }
    getTime(fibonacci, 40)
    
    // memoization化斐波那契数列
    const fibonacciWithCache = (function () {
      // 设置缓存队列
      const cacheList = [0, 1, 1, 2]
      return function _fibonacciWithCache (n) {
        // 如果缓存队列中没有该运算结果,则计算出结果并加入缓存队列中
        if (!cacheList[n]) 
          cacheList[n] = _fibonacciWithCache(n - 1) + _fibonacciWithCache(n - 2)
        return cacheList[n]
      }
    }())
    getTime(fibonacciWithCache, 40)
    

    分别用非缓存与缓存方式分别实现递归方式的斐波那契数列

    计算的耗费时间如下:

    用时:1554毫秒,结果:102334155

    用时:0毫秒,结果:102334155

    前者运行了331160281次,而后者仅运行了75次

    工具方法

    // memoization实现
    const memoize = function (fn) {
      const cacheMap = {}
      return function (key) {
        if(!cacheMap[key]) cacheMap[key] = fn.apply(this, arguments)
        return cacheMap[key]
      }
    }
    const newFibonacci = memoize(fibonacci)
    
    // lodash中的实现方式
    const lodashMemoize = function(func, hasher) {
      var memoize = function(key) {
        var cache = memoize.cache;
        var address = '' + (hasher ? hasher.apply(this, arguments) : key);
        if (!_.has(cache, address))
          cache[address] = func.apply(this, arguments);
        return cache[address];
      };
      memoize.cache = {};
      return memoize;
    };
    const newLodashMemoize = memoize(fibonacci)
    

    两种方式,loadsh添加了对键值的定制化方法,缓存会绑定在返回的方法之上,虽方法的销毁一同销毁。剩下的思路都是一样的,现实中我们写工具类的时候可以用map来代替object

    但需要注意的是,这种方法仅对性能耗费较大的运算有缓存优势,而对象上面实现斐波那契数列的递归方式对单次结果的返回无影响,即它只对计算结果进行了缓存,但对计算过程并没有优化。
    由于递归的特殊性,在写代码时就注意memoization的性能考虑是更好的选择。

    现实中应用

    前端在现实项目中很少用到递归或者性能消耗较大的例子,但比如react这种状态变化会多次触发渲染的框架,应用memoization方式避免重复运算提高性能,是常见的方式。

    在现实中应用需要注意的是,大量的缓存会占据内存空间,导致空间浪费。当我们不能控制好缓存的大小时,谨慎使用。

    现实项目中,诸如memoize-one的插件是更好的选择,他只缓存你上一次的计算结果,这种特性在减少覆盖率的情况下也减轻了缓存的负担。并且与react特性特别的match。可以清除react本身大部分由于大量状态变动导致的频繁render的情况。

    相关文章

      网友评论

          本文标题:memoization的简介和应用

          本文链接:https://www.haomeiwen.com/subject/qxsgrctx.html