美文网首页
js性能优化-利用备忘模式进行结果缓存

js性能优化-利用备忘模式进行结果缓存

作者: 0月 | 来源:发表于2019-12-28 15:39 被阅读0次

    计算优化

    对于不变的结果能缓存就尽量缓存,这样子就减少每次使用的时候进行多次计算,浪费性能。
    如:

    • 同步结果:
      利用 备忘模式 创建一个备忘函数 memorize;
      将同步执行的函数fn进行备忘,这个函数fn的计算结果就会缓存起来,当你传入相同的参数的时候就会直接返回缓存的结果
    function memorize (fn) {
      const cache = {}
      return function(){
        const args = [].slice.call(arguments)
        const key = JSON.stringify(args)
        return cache[key] || (cache[key] = fn.apply(fn, args))
      }
    }
    
    const add = (x, y) => x + y
    
    const addFn = memorize(add)
    
    const res = addFn(1,2) // 3, 第一次执行add方法得结果
    const res = addFn(1,2) // 3 ,第二次从cache中拿结果
    

    上面的addFn 就是经过备忘的函数,里面利用闭包将计算结果缓存起来,再次传入相同的参数调用时就会从cache中拿结果而不是再次计算。这样子的好处就是对于多次计算复杂的过程有很明显性能提升,缺点也很明显:参数一变,内存消耗就会增大,因为key是由参数决定的。这也是闭包的注意点,消耗内存不释放,那这里是否可以优化?当然可以,可以定义cache的一个最大上限,然后当存满时可用算法FIFO 或者 LRU释放。其实vue源码中也有用到这么一个函数,思想大体上一致,在vue/src/shared/util.js中


    cached.png
    • 异步结果
      对于异步结果就不能直接用memorize函数进行备忘了,但是也可以变通改造一下
    // 异步函数的备忘函数
    function AsyncMemorize (AsyncFn) {
      const cache = {}
      return function(){
        const args = [].slice.call(arguments)
        const key = JSON.stringify(args)
        return new Promise (function (resolve, reject) {
          if (cache.hasOwnProperty(key)){
            resolve(cache[key])
            return
          }
          AsyncFn.apply(AsyncFn, args).then(res => {
            cache[key] = res
            resolve(res)
         }).catch(e => reject(e))
        })
      }
    }
    

    实验一下,假如有个异步函数asyncAdd

    const asyncAdd = (x, y) => {
      return new Promise(resolve => {
         setTimeout(() => resolve(x + y), 1000)
      })
    }
    

    用法是:

    asyncAdd(1,2).then(res => console.log(res)) // res : 3
    

    那么对它进行备忘:

    const asyncAdder = AsyncMemorize(asyncAdd)
    asyncAdder(1,2).then(res1 => console.log(res1)) // 第一次等待1秒后输出res1: 3
    asyncAdder(1,2).then(res1 => console.log(res1)) // 第二次不用等待1秒后就直接输出res1: 3
    

    例子如下:


    image.png

    可以看到:
    第一次执行asyncAdder(1,2).then(res1 => console.log(res1))的时候,
    控制台先是打印Promise{<pending>} ,再打印结果3

    第二次执行asyncAdder(1,2).then(res1 => console.log(res1))的时候,
    控制台先是打印结果3 ,再打印Promise{<pending>}

    实际应用场景:

    前端需要通过ajax请求后端拿一个结果,这个结果是短时期或者长时期不会变的,那么就可以对这个结果进行备忘缓存,多次用到的时候只发一次请求,不用每次拿都发一次请求,起到节省带宽,减少用户等待时间、提升用户体验的作用。

    总结

    以上就是利用备忘模式分别对同步、异步结果进行缓存的使用方式,算是对计算性能的一个优化策略,值得参考。

    相关文章

      网友评论

          本文标题:js性能优化-利用备忘模式进行结果缓存

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