HomeLập trìnhJavaScriptCách sử dụng...

Cách sử dụng Memoize để lưu trữ kết quả chức năng JavaScript và tăng tốc mã của bạn


Hàm là một phần không thể thiếu trong lập trình. Chúng giúp thêm mô-đunkhả năng sử dụng lại vào mã của chúng tôi.

Việc chia chương trình của chúng ta thành các phần bằng cách sử dụng các hàm mà chúng ta có thể gọi sau này để thực hiện một số hành động hữu ích là điều khá phổ biến.

Đôi khi, một hàm có thể trở nên đắt đỏ khi gọi nhiều lần (ví dụ: hàm tính giai thừa của một số). Nhưng có một cách chúng ta có thể tối ưu hóa các chức năng như vậy và làm cho chúng thực thi nhanh hơn nhiều: bộ nhớ đệm.

Ví dụ: giả sử chúng ta có một function để trả về giai thừa của một số:

function factorial(n) {
    // Calculations: n * (n-1) * (n-2) * ... (2) * (1)
    return factorial
}

Tuyệt vời, bây giờ chúng ta hãy tìm factorial(50). Máy tính sẽ thực hiện các phép tính và trả về cho chúng ta câu trả lời cuối cùng, ngọt ngào!

Khi đã xong, chúng ta hãy tìm factorial(51). Máy tính lại thực hiện một số phép tính và cho chúng tôi kết quả, nhưng bạn có thể nhận thấy rằng chúng tôi đã lặp lại một số bước mà lẽ ra có thể tránh được. Một cách tối ưu hóa sẽ là:

factorial(51) = factorial(50) * 51

Nhưng của chúng tôi function thực hiện các phép tính từ đầu mỗi khi nó được gọi:

factorial(51) = 51 * 50 * 49 * ... * 2 * 1

Sẽ không hay sao nếu bằng cách nào đó chúng ta factorial chức năng có thể nhớ các giá trị từ các tính toán trước đó của nó và sử dụng chúng để tăng tốc độ thực thi không?

đến ghi nhớmột cách cho chúng tôi function để ghi nhớ (cache) kết quả. Bây giờ bạn đã hiểu cơ bản về những gì chúng tôi đang cố gắng đạt được, đây là định nghĩa chính thức:

ghi nhớ là một kỹ thuật tối ưu hóa được sử dụng chủ yếu để tăng tốc các chương trình máy tính bằng cách lưu trữ kết quả của các cuộc gọi chức năng đắt tiền và trả về kết quả được lưu trong bộ nhớ cache khi các đầu vào tương tự xảy ra lần nữa

ghi nhớ trong điều kiện đơn giản có nghĩa là ghi nhớ hoặc lưu trữ trong bộ nhớ. Hàm được ghi nhớ thường nhanh hơn bởi vì nếu hàm được gọi sau đó với (các) giá trị trước đó, thì thay vì thực thi hàm, chúng ta sẽ tìm nạp kết quả từ bộ đệm.

Đọc thêm  Cách hủy cấu trúc đối tượng trong JavaScript

Đây là một chức năng ghi nhớ đơn giản có thể trông như thế nào (và đây là CodePen trong trường hợp bạn muốn tương tác với nó):

// a simple function to add something
const add = (n) => (n + 10);
add(9);
// a simple memoized function to add something
const memoizedAdd = () => {
  let cache = {};
  return (n) => {
    if (n in cache) {
      console.log('Fetching from cache');
      return cache[n];
    }
    else {
      console.log('Calculating result');
      let result = n + 10;
      cache[n] = result;
      return result;
    }
  }
}
// returned function from memoizedAdd
const newAdd = memoizedAdd();
console.log(newAdd(9)); // calculated
console.log(newAdd(9)); // cached

Ghi nhớ takeaways

Một số điểm rút ra từ đoạn mã trên là:

  • memoizedAdd trả về một function được gọi sau này. Điều này là có thể bởi vì trong JavaScript, các hàm là các đối tượng hạng nhất cho phép chúng ta sử dụng chúng như các hàm bậc cao hơn và trả về một hàm khác.
  • cache có thể nhớ nó giá trị vì hàm được trả về có bao đóng trên nó.
  • Điều cần thiết là chức năng ghi nhớ là thuần túy. Một hàm thuần túy sẽ trả về cùng một đầu ra cho một đầu vào cụ thể bất kể nó được gọi bao nhiêu lần, điều này làm cho cache làm việc như mong đợi.

Viết của riêng bạn memoize chức năng

Đoạn mã trước hoạt động tốt nhưng nếu chúng ta muốn biến bất kỳ chức năng nào thành một chức năng được ghi nhớ thì sao?

Đây là cách viết chức năng ghi nhớ của riêng bạn (codepen):

// a simple pure function to get a value adding 10
const add = (n) => (n + 10);
console.log('Simple call', add(3));
// a simple memoize function that takes in a function
// and returns a memoized function
const memoize = (fn) => {
  let cache = {};
  return (...args) => {
    let n = args[0];  // just taking one argument here
    if (n in cache) {
      console.log('Fetching from cache');
      return cache[n];
    }
    else {
      console.log('Calculating result');
      let result = fn(n);
      cache[n] = result;
      return result;
    }
  }
}
// creating a memoized function for the 'add' pure function
const memoizedAdd = memoize(add);
console.log(memoizedAdd(3));  // calculated
console.log(memoizedAdd(3));  // cached
console.log(memoizedAdd(4));  // calculated
console.log(memoizedAdd(4));  // cached

Bây giờ thì thật tuyệt! đơn giản này memoize chức năng sẽ gói bất kỳ đơn giản function thành một tương đương ghi nhớ. Mã hoạt động tốt cho các chức năng đơn giản và có thể dễ dàng điều chỉnh để xử lý bất kỳ số lượng nào. arguments theo nhu cầu của bạn. Một cách khác là tận dụng một số thư viện thực tế như:

Đọc thêm  Hướng dẫn về mảng đối tượng JavaScript – Cách tạo, cập nhật và lặp qua các đối tượng bằng các phương thức mảng JS

Ghi nhớ các hàm đệ quy

Nếu bạn thử chuyển một hàm đệ quy tới memoize chức năng trên hoặc _.memoize từ Lodash, kết quả sẽ không như mong đợi vì hàm đệ quy trong các lệnh gọi tiếp theo của nó sẽ tự gọi chính nó thay vì hàm ghi nhớ, do đó không sử dụng được cache.

Chỉ cần đảm bảo rằng hàm đệ quy của bạn đang gọi hàm ghi nhớ. Đây là cách bạn có thể điều chỉnh một ví dụ giai thừa trong sách giáo khoa (codepen):

// same memoize function from before
const memoize = (fn) => {
  let cache = {};
  return (...args) => {
    let n = args[0];
    if (n in cache) {
      console.log('Fetching from cache', n);
      return cache[n];
    }
    else {
      console.log('Calculating result', n);
      let result = fn(n);
      cache[n] = result;
      return result;
    }
  }
}
const factorial = memoize(
  (x) => {
    if (x === 0) {
      return 1;
    }
    else {
      return x * factorial(x - 1);
    }
  }
);
console.log(factorial(5)); // calculated
console.log(factorial(6)); // calculated for 6 and cached for 5

Một vài điểm cần lưu ý từ mã này:

  • Các factorial hàm đang gọi đệ quy một phiên bản đã ghi nhớ của chính nó.
  • Hàm ghi nhớ đang lưu vào bộ đệm các giá trị của các giai thừa trước đó giúp cải thiện đáng kể các phép tính vì chúng có thể được sử dụng lại factorial(6) = 6 * factorial(5)

Ghi nhớ có giống như lưu vào bộ nhớ đệm không?

Đúng loại của. Ghi nhớ thực sự là một loại bộ nhớ đệm cụ thể. Mặc dù bộ nhớ đệm nói chung có thể đề cập đến bất kỳ kỹ thuật lưu trữ nào (như bộ nhớ đệm HTTP) để sử dụng trong tương lai, nhưng việc ghi nhớ cụ thể liên quan đến bộ nhớ đệm giá trị trả về của a function.

Khi nào cần ghi nhớ các chức năng của bạn

Mặc dù có vẻ như tính năng ghi nhớ có thể được sử dụng với tất cả các chức năng, nhưng thực tế nó có một số trường hợp sử dụng hạn chế:

  • Để ghi nhớ một hàm, hàm đó phải thuần túy để các giá trị trả về giống nhau cho cùng một đầu vào mỗi lần
  • Ghi nhớ là sự đánh đổi giữa không gian được thêm vào và tốc độ được thêm vào và do đó chỉ có ý nghĩa đối với các chức năng có phạm vi đầu vào hạn chế để có thể sử dụng các giá trị được lưu trong bộ nhớ cache thường xuyên hơn
  • Có vẻ như bạn nên ghi nhớ các lệnh gọi API của mình, tuy nhiên điều đó là không cần thiết vì trình duyệt sẽ tự động lưu chúng vào bộ đệm cho bạn. Xem bộ nhớ đệm HTTP để biết thêm chi tiết
  • Trường hợp sử dụng tốt nhất mà tôi tìm thấy cho các chức năng được ghi nhớ là cho các chức năng tính toán nặng có thể cải thiện đáng kể hiệu suất (giai thừa và fibonacci không phải là ví dụ thực sự tốt trong thế giới thực)
  • Nếu bạn thích React/Redux, bạn có thể kiểm tra chọn lại cái nào sử dụng bộ chọn ghi nhớ để đảm bảo rằng các tính toán chỉ xảy ra khi thay đổi xảy ra trong một phần liên quan của cây trạng thái.
Đọc thêm  Thay đổi văn bản bằng javaScript onClick trợ giúp!

đọc thêm

Các liên kết sau đây có thể hữu ích nếu bạn muốn biết thêm về một số chủ đề từ bài viết này một cách chi tiết hơn:

Tôi hy vọng bài viết này hữu ích cho bạn và bạn đã hiểu rõ hơn về ghi nhớ trong JavaScript 🙂


Bạn có thể theo dõi tôi trên Twitter để cập nhật mới nhất. Tôi cũng đã bắt đầu đăng nhiều bài viết gần đây trên blog cá nhân của mình.





Zik.vn – Biên dịch & Biên soạn Lại

spot_img

Create a website from scratch

Just drag and drop elements in a page to get started with Newspaper Theme.

Buy Now ⟶

Bài viết liên quang

DMCA.com Protection Status