안녕하세요!모든 것을 요구하는 것을 멈추다: 간단한 회고록 안내서

야, 2분 전에 검색한 데이터를 요청하기 위해 비싼 함수 호출을 하지 마!어떻게 하냐고요?이것은 매우 간단하다. 당연히 비망록을 써야 한다.

정의
기억화는 동적 기획의 최적화 기술로 비싼 함수를 호출하는 값을 메모리에 저장하는 것과 관련된다. 이렇게 하면 이 값을 다시 검색해야 할 때 더욱 빠르고 빠르게 할 수 있다.

의 목적
  • 비망록의 기본 개념을 이해한다.
  • 비망록을 언제 사용해야 하는지 식별한다.
  • 메모를 사용하지 말아야 하는 시기를 식별합니다.

  • 선결 조건
    필요하지는 않지만 다음과 같은 부분에 대해 어느 정도 알고 있다면 이 글은 더욱 잘 이해할 수 있을 것입니다.
  • Closures
  • Higher order functions
  • Pure functions
  • Currying

  • 개술
    기억은 캐시 형식의 하나로 함수의 반환 값을 메모리에 저장하는 것과 관련이 있다.이 함수를 호출할 때 캐시 대상을 검사해서 전달된 입력의 값이 존재하는지 확인하고, 존재하면 캐시 결과를 되돌려줍니다.캐시에 이 값이 존재하지 않으면 대량으로 계산되고 되돌아오는 값도 캐시에 저장되어 다음에 필요할 때 더욱 빨리 검색할 수 있습니다.
    우리 기본적인 예를 하나 보자...

    기본 예

    1. 클립 생성
    우리는 클라이언트 encapsulate 캐시 대상을 사용하고 빈 대상으로 초기화합니다.캐시를 검사하고 힘든 작업을 완성하는 기능도 추가했습니다.
    const memoizeFn = () => {
      // our cache object
      let cache = {};
    
      return (input) => {
        // the contents of the function which will be doing the heavy work
      }
    }
    

    2. 패키지에서 함수를 만듭니다
    이 예에서, 우리는 입력을 배로 늘리는 함수를 사용할 것이다. 이것은 분명히 요구가 높은 함수는 아니지만, 이것은 이 예에 적용된다.
    const memoizeFn = () => {
      let cache = {};
    
      return (input) => {
        const result = input * 2;
    
        return result;
      }
    }
    

    3. 지금은 추억의 시간이다
    우리가 진정으로 해야 할 일은if를 추가하는 것이다.else는 이 값이 캐시에 존재하는지 확인하기 위해 내부 함수에 조건을 설정합니다.
    const memoizeFn = () => {
      let cache = {};
    
      return (input) => {
        // lets log our cache here so we can see what is stored
        // when we call our function
        console.log(cache);
    
        // have we got the result of this input already from a previous call?
        if (cache[input]) {
         // nice, we do! No need for any heavy computation here!
          return cache[input];
        } else {
          // it’s not in our cache!
          const result = input * 2;
    
          // store the result in the cache so next time it is called with this input
          // we can retrieve it from our cache
          cache[input] = result;
    
          return result;
        }
      }
    }
    
    위의 예에서 볼 수 있듯이, 우리는memoizeFn을 닫아서 빈 대상으로 캐시를 초기화하고, 계산량이 많은 순수 함수를 되돌려줍니다. 이 함수는 하나의 숫자를 입력으로 합니다.이 입력은 캐시 대상의 키로 사용됩니다.이 함수를 호출할 때마다 캐시를 검사해서 입력한 결과가 있는지 확인합니다.

    4. 실제 효과를 살펴보자
    // this invokes the first function and initialises our cache object
    const doubleInput = memoizeFn();
    
    doubleInput(10); // console log = {}
    doubleInput(20); // console log = {10: 20}
    
    // 10 is in our cache. No heavy computation needed
    doubleInput(10); // console log = {10: 20, 20: 40}
    
    memoizeFn이 호출되어 더블 인풋 변수에 분배되었습니다. 이 변수는 호출될 때 캐시 대상에 접근할 수 있습니다.우선, 값이 10인 더블 인풋을 호출합니다. 캐시 대상이 비어 있기 때문에, 이 숫자를 배로 늘리는 번거로운 계산이 필요합니다.다음에 우리는 20을 입력으로 할 것이다. 마찬가지로 함수의 복잡한 계산 부분을 통해 실행해야 한다. 왜냐하면 이것은 우리의 캐시에 존재하지 않기 때문이다.마지막으로, 우리는 다시 10을 우리의 함수에 전달하여 캐시 대상을 검사하여 키가 10인 값이 존재하는지 확인합니다. 이것은 확실히 존재하기 때문에 캐시에서 이 값을 검색합니다.

    그렇다면 현실 세계에서 나는 어디에서 그것을 사용할 것인가?
    좀 더 진실한 예를 봅시다.만약 당신이 SPA 소셜 미디어 플랫폼을 만들고 있다면 사용자는 그 중의 친구 목록을 가지고 있을 수 있으며, 그 중의 한 친구를 클릭하면 그 사용자의 개인 자료를 되돌려줄 수 있다.이 구성 파일과 관련된 데이터를 반환하려면 API를 호출해야 합니다.맞습니다.그러나 사용자가 웹 사이트를 방문했을 때 이전에 방문한 프로필로 돌아오면 이 API를 다시 호출하시겠습니까?우리는 할 수 있다. 아니면 비망록을 사용할 수 있다.다음은 메서드입니다.
    const memoizeUser = () => {
      let cache = {};
    
      return async (userId) => {
        if (cache[userId]) {
          return cache[userId];
        }
    
        // it's not in our cache, we need to hit the API
        // this could take a little while...
        const data = await fetch(`https://myapi.com/users/{userId}`);
    
        const user = await data.json();
    
        cache[userId] = user;
    
        return user;
      }
    }
    
    이것은 우리의 함수로 첫 번째 예와 매우 비슷해 보인다.다음은 그것을 어떻게 사용하는지 봅시다.
    // get access to the cache
    const getUser = memoizeUser();
    
    // add a click event listener to a button which gets a user’s profile
    // this button will have an id of the users id that it accesses
    document.querySelector('#getUserButton').addEventListener('click', async (e) => {
      const userId = e.target.id;
    
      // have we visited this user before? 
      const userData = await getUser(userId); 
    
      // rest of function which returns users profile using the
      // userData retrieved above
    });
    
    사용자 프로필을 눌렀을 때, 우리는 단추에서 사용자 id를 가져와 getUser를 호출해서 사용자 데이터를 되돌려줍니다.이것은 이전에 이 사용자 프로필에 접근했을 때 캐시에 이미 있는 API를 명중시킬 것입니다. 이 경우 서버를 호출할 필요가 없고 캐시에서 데이터를 직접 얻을 수 있습니다.
    아주 간단하죠?이것은 기억의 기초 지식을 포괄한다.

    승진할 때가 됐어요.
    만약 당신이 정말로 똑똑해지고 싶다면, 복잡한 계산 함수를 패키지 자체에 전달할 수도 있고, 패키지 자체는 가변 수량의 매개 변수가 필요할 수도 있다.
    const memoize = (fn) => {
      let cache = {};
    
      return (...args) => {
        // as this now takes variable arguments, we want to create a unique key
        // you would need to define this hash function yourself
        const key = hash(args);
    
        if (!cache[key]) {
          cache[key] = fn(...args);
        }
    
        return cache[key];
      }
    }
    
    // some functions we can pass to memoize
    const add = (num1, num2) => num1 + num2;
    const subtract = (num1, num2) => num1 - num2;
    
    // these 2 will have different cache objects thanks to closures
    const add2Numbers = memoize(add);
    const subtract2Numbers = memoize(subtract);
    
    const result1 = add2Numbers(10, 20);
    const result2 = add2Numbers(20, 30);
    
    const result3 = subtract2Numbers(10, 5);
    
    
    멋있죠?우리는 이memoize 패키지를 정의하고 여러 함수를 전달할 수 있으며, 함수마다 서로 다른 수량의 매개 변수를 받아들일 수 있다.

    어떤 것은 괜찮고 어떤 것은 안 된다
    기억은 언제 쓸모가 있습니까?
  • API에서 고정 데이터를 읽어들일 때
  • 엄격한 계산을 실행할 때 주어진 입력에 대해 이런 계산은 정기적으로 중복될 수 있다.
  • 회고록 언제 안 써요?
  • 정기적으로 변경되는 API에서 데이터를 읽어들일 때
  • 간단한 함수 호출.

  • 총결산
  • 회고록은 캐시 형식으로 저장 요구가 높은 기능에 사용된 결과이다.
  • 이것은 간단한 기술로 기존 코드 라이브러리에서 쉽게 실현하여 성능을 향상시킬 수 있다.
  • 고정 데이터 API와 자주 발생하는 번거로운 계산 기능을 처리할 때 기억 기능이 매우 유용하다.
  • 좋은 웹페이지 즐겨찾기