首页 > 其他分享 >记忆函数的实战应用

记忆函数的实战应用

时间:2024-01-20 21:45:11浏览次数:27  
标签:实战 function 调用 const 函数 记忆 return

力扣2623.记忆函数

今天在力扣做了一道题:使用JavaScript实现记忆函数,所谓记忆函数就是一个对于相同的输入永远不会被调用两次的函数。相反,它将返回一个缓存值

以下是使用哈希表实现的方法:

/**
 * @param {Function} fn
 * @return {Function}
 */
function memoize(fn) {
    const map = new Map(); 
    return function(...args) {
        const item = args.join(',')
        if(!map.has(item)) {
            map.set(item, fn(...args))
        }
        return map.get(item)
    }
}


/** 
 * let callCount = 0;
 * const memoizedFn = memoize(function (a, b) {
 *	 callCount += 1;
 *   return a + b;
 * })
 * memoizedFn(2, 3) // 5
 * memoizedFn(2, 3) // 5
 * console.log(callCount) // 1 
 */

需要说明的是,记忆函数只对纯函数(Pure function)有效,也就是对那些给定相同的输入,始终返回相同的输出,并且没有任何副作用的函数

假如忽略这一点,可能会导致使用具有副作用的函数,会执行相应的过程,但每次后续调用都不会再得到新的结果。

Web开发中的记忆化

记忆化作为一种重要的思想,在Web开发中有很多实战:

缓存网站文件

大型网站通常由许多 JavaScript 文件组成,在用户访问不同页面时会动态下载这些文件。有时会采用一种模式,其中文件名基于文件内容的哈希值。这样,当 Web 浏览器请求已经在之前请求过的文件名时,它可以从磁盘上本地加载文件,而不必重新下载它。

React 组件

React 是一个非常流行的用于构建用户界面的库,尤其适用于单页面应用程序。其核心原则之一是将应用程序分解为单独的 组件。每个组件负责渲染应用程序HTML的不同部分。

例如,你可能有一个组件如下:

const TitleComponent = (props) => {
  return <h1>{props.title}</h1>;
};

上面的函数将在每次父组件渲染时调用,即使 title 没有更改。通过在其上调用 React.memo,可以提高性能,避免不必要的渲染。

const TitleComponent = React.memo((props) => {
  return <h1>{props.title}</h1>;
});

现在,TitleComponent 只有在 title 发生变化时才会重新渲染,从而提高了应用程序的性能。

缓存 API 调用

假设你有一个函数,用于向API发送网络请求以访问数据库中的键值对。

async function getValue(key) {
  // 数据库请求逻辑
}
const getValueMemoized = memoize(getValue);

现在,getValueMemoized 将仅为每个键进行一次网络请求,可能大大提高性能。需要注意的是,由于 getValue 是异步的,它将返回一个 Promise 而不是实际值。对于这种用例,这实际上是最理想的,因为即使在第一次请求返回值之前调用两次,它仍然只会进行一次网络请求。

记忆化网络请求的一个潜在缺点是数据陈旧的风险。如果数据库中与特定键关联的值发生更改,记忆化函数可能仍然返回旧的缓存结果,使用户无法看到更新。

处理这种情况的几种方法:

  1. 始终向 API 发送请求,询问值是否已更改。
  2. 使用 WebSocket 订阅数据库中值的更改。
  3. 为值提供 过期时间,以使用户至少不会看到太过时的数据。

算法中的记忆化

记忆化的一个经典应用是在动态规划中,将问题分解为若干子问题。这些子问题可以表示为函数调用,其中许多函数调用多次且使用相同的输入,因此可以进行优化。

动态规划极大提高效率的一个经典示例是计算斐波那契数。

function fib(n) {
  if (n <= 1) return n;
  return fib(n - 1) + fib(n - 2);
}
fib(100); // 耗时多年

但是,通过不再使用相同的输入两次调用 fib,我们可以在 O(n)的时间内计算斐波那契数。

const cache = new Map();
function fib(n) {
  if (n <= 1) return n;
  if (cache.has(n)) {
    return cache.get(n);
  }
  const result = fib(n - 1) + fib(n - 2);
  cache.set(n, result);
  return result;
}
fib(100); // 几乎立即解决

我们是否可以只是调用了fib的第一个实现,然后在其上写了memoizedFib = memoize(fib);以获得相同的性能优化?不幸的是,不能。fib 的原始实现引用了自身(未记忆化版本)。因此,如果调用 memoizedFib(100),缓存只会添加一个键(100),仍然需要数年时间才能计算。这是 JavaScript 的一个基本限制(Python 没有此问题)。

标签:实战,function,调用,const,函数,记忆,return
From: https://www.cnblogs.com/gfhcg/p/17977177

相关文章

  • Python实战:selenium模拟浏览器运行,获取软科网站2023中国大学排名
    Python实战:selenium模拟浏览器运行,获取软科网站2023中国大学排名在爬取一些加密的网页时,可以使用selenium模拟浏览器运行,再从网页中提取想要的数据。使用的库本文使用到的Python库有:selenium、bs4、pandas使用selenium解决网页的反爬使用bs4对html网页进行解析和提取数据......
  • Ingress企业实战:部署多个Ingress控制器篇
    背景在大规模集群场景中,部分服务需要通过公网Ingress对外提供服务访问,但是有部分服务只对内提供服务,不允许使用公网访问,仅支持内部服务间调用,此时可以通过部署两套独立的Ingress来实现,一套支持公网访问,一套仅支持内网访问。接下来,我们通过最佳实践进行实现喽!架构图最佳实践说明......
  • js 异步函数策略
    因为简单实用,所以异步函数很快成为JavaScript项目使用最广泛的特性之一。不过,在使用异步函数时,还是有些问题要注意。实现sleep()很多人在刚开始学习JavaScript时,想找到一个类似Java中Thread.sleep()之类的函数,好在程序中加入非阻塞的暂停。以前,这个需求基本上都通过set......
  • js 异步函数的返回值
    函数可以得到它返回的期约:asyncfunctionfoo(){console.log(1);return3;}//给返回的期约添加一个解决处理程序foo().then(console.log);console.log(2);//1//2//3当然,直接返回一个期约对象也是一样的:asyncfunctionfoo(){console.log(1);returnProm......
  • std::declval 元函数
    declval用于非求值上下文中declval原形:template<typename_Tp>autodeclval()noexcept->decltype(__declval<_Tp>(0)){static_assert(__declval_protector<_Tp>::__stop, "declval()mustnotbeused!");return__declval&l......
  • 相似单词记忆表
    相似单词记忆Aalone:独自,单独,孤独地,只along:沿着,顺着,向前,与...一起appear:出现,起源,问世,似乎,好像disappear:消失,失踪attract:吸引,引起attractive:有吸引力的,漂亮的Bbelow:在...下面lower:下面的,把...放低beat:打败,难过,胜过heat:热,热度heart:心脏,内心,重点,中央,心形Cchange:改......
  • Ingress企业实战:金丝雀发布与蓝绿发布
    背景现如今,越来越多的应用采用了微服务架构,这也导致了应用数量相比传统模式更多,管理更加复杂,发布更加频繁,如果直接将新版本上线发布给全部用户。一旦遇到线上事故(或BUG),对用户的影响极大,解决问题周期较长,甚至有时不得不回滚到前一版本,严重影响了用户体验。为了保证整体系统的稳定,风......
  • Python中的回调函数
    先来看一个程序:deff1():print(2)return1deff2(a):print(3)returnaprint(f2(f1()))这个程序,在调用时,f2会先等待f1调用完毕,返回1之后,再进行调用,所以会输出2、3、1,但是若这样改写程序deff1():print(2)return1deff2(f):prin......
  • 日期函数——来源网络,方便查阅
    DateUtils时间单元,非常有用。记得引用这个单元,不然不能用。CompareDate比较两个日期时间值日期部分的大小CompareDateTime比较两个日期时间值的大小CompareTime比较两个日期时间值时间部分的大小DateOf去除日期时间值的时间部分DateTimeToJulianDate转换日期时间值为儒略日......
  • 积性函数学习笔记
    积性函数定义积性函数:\(f(x)\)满足\(\forall\gcd(a,b)=1,f(ab)=f(a)f(b)\)若没有\(\gcd(a,b)=1\)的性质,则为完全积性函数。性质性质1:\(f(x),g(x)\)是积性函数\(\implies\)\(f\timesg\)是积性函数,\(f\divg\)是积性函数证明略。性质2:狄利克雷(Dirichlet)卷积\(......