- vừa được xem lúc

Javascript Memorization - Cải thiện performance

0 0 8

Người đăng: Nguyen Xuan Vinh

Theo Viblo Asia

Hello, xin chào tất cả mọi người, chúc mọi người năm mới vui vẻ vẻ tràn ngập niềm vui ạ. Để ăn tết vui vẻ mà không quên bổ sung kiến thức mới thì hôm nay mình xin chia sẽ với các bạn về một chủ đề cũng khá hay trong Javascript, đó là Memorization.

Có lẽ rất nhiều bạn đã nghe tới Memorization khi mà làm việc với Reactjs, như là useCallback(), useMemo() và chỉ hiểu nó có tác dụng là tránh tính toán lại không cần thiết, nhưng có thể chưa hiểu sâu là nó hoạt động như thế nào, hôm nay mình sẽ cũng làm một vài ví dụ về Memorization trong Javascript để các bạn có thể hiểu hơn về nó nhé!

1. Ví dụ 1

Sau đây là ví dụ đơn giản về hàm cộng 2 số:

function sum(number) { return number + 789;
}

Các bạn có thể thấy khi bạn truyền một một tham số vào hàm sum(2000) thì nó sẽ tính toán và cho ra kết quả, đương nhiên là sẽ không vấn đề gì với máy tính với những phép tính toán đơn giản như vậy.

Nhưng nó vẫn sẽ tính toán lại những số mà bạn đã truyền vào hàm sum(2000) trước đó => với những tính toán expensive computation thì sao?

Nó sẽ phải tính toán lại sẽ gây ít nhiều đến hiệu suất. Vậy giờ mình sẽ áp dụng cách khác thử xem nhé.

function memoized() { let cache = {}; return function sum(number) { if (number in cache) { return cache[number] } else { cache[number] = number + 768; return cache[number]; } }
}

Giải thích: Ở đoạn code trên bạn có thể thấy một hàm memoized() return về hàm sum(number) (gọi là Closure bạn có thể tìm hiểu tại ĐÂY). Nhưng nói chung mình sẽ tóm tắt lại Closure là:

A closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time. - Theo https://developer.mozilla.org/

Clusure cho phép truy cập vào biến, tham số của một outer function từ một inner function và nó có thể truy cập ngay cả khi mà outer function đã được đóng lại.

Cùng liệt kê để hiểu thêm nhé:

  • Biến cache: Thằng này có tác dụng là lưu trữ kểt quả của những thằng mà mình cần truyền vào hàm sum(number), để sau đó mình có truyền lại thì nó chỉ cần lấy ra kết quả mà không cần phải tính lại.
  • If else trong sum(): Thằng này sẽ check xem là nếu tham số truyền vào mà đã lưu trong thằng cache thì sẽ không tính toán nữa mà chỉ cần return về kết quả thôi. Còn không thì tính toán và lưu vào cache.
function memoized() { let cache = {}; return function sum(number) { if (number in cache) { return cache[number] } else { cache[number] = number + 768; return cache[number]; } }
} const memoizedFunctionCall = memoized(); memoizedFunctionCall(2000) // Output: 2789 | Cần tính toán vì chưa cache
memoizedFunctionCall(2000) // Output: 2789 | giá trị này đã cache nên không cần tính toán lại

Như vậy bạn có thể hiểu hơn chưa, nếu chưa thì mình làm thêm một ví dụ nữa nhé!

2. Ví dụ 2

Mình sẽ tạo một hàm sử dụng recursive, hàm này sẽ chạy liên tục đến khi param truyền vào là <= 1. Bạn có thể tìm hiểu về recursive tại đây.

function FibSequence(n) { if (n <= 1) { return 1; } else { return FibSequence(n - 1) + FibSequence(n - 2); }
}
FibSequence(5) // Output: 8

Bạn có thể thấy ở đoạn code trên hàm FibSequence() sẽ chạy liên tục đến khi nào n <= 1 có nghĩa là sẽ chạy FibSequence(n - 1) rồi FibSequence(n - 2), vậy độ phức tạp của nó sẽ là O(n^2) (thực ra mình cũng không rành về cái này, chỉ hiểu là nó phức tạp, phiền phức ?)) => Hiệu suất không tốt.

Vậy không tốt chổ nào nhỉ?

FibSequence(5) calls FibSequence(4) and FibSequence(3)
FibSequence(4) calls FibSequence(3) and FibSequence(2)
FibSequence(3) calls FibSequence(2) and FibSequence(1) // Nó sẽ call những lần như sau
FibSequence(5)
FibSequence(4)
FibSequence(3)
FibSequence(3) // Thằng này lặp lại rồi nè
FibSequence(2)
FibSequence(2) // Thằng này nữa
FibSequence(1)

Vậy mình sẽ sửa lại đoạn code trên thành:

function memoized(n, cache) { cache = cache ? cache : {}; if (cache[n]) { return cache[n]; } if (n < 2) { return 1; } else { cache[n] = memoized(n - 1, cache) + memoized(n - 2, cache); return cache[n]; }
} memoized(5) // Outputs 8

Như vậy thì nhìn đẹp hơn phải hông nào, các bạn có thể thấy ở 2 ví dụ mình có khai báo biến Object để lưu dạng keys values để có thể cache giá trị vào. Kỹ thuật này cũng đơn giản phải hông nè, à còn Closure nữa các bạn tự tìm hiểu thêm nhé.

Chúc các bạn năm mới vv, hp và nhiều thành công hơn nha, xin cảm ơn ❤️

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Typescript - Sự khác nhau giữa Typescript và Javascript

Typescript là gì. TypeScript là một ngôn ngữ giúp cung cấp quy mô lớn hơn so với JavaScript.

0 0 528

- vừa được xem lúc

Bạn đã biết các tips này khi làm việc với chuỗi trong JavaScript chưa ?

Hi xin chào các bạn, tiếp tục chuỗi chủ đề về cái thằng JavaScript này, hôm nay mình sẽ giới thiệu cho các bạn một số thủ thuật hay ho khi làm việc với chuỗi trong JavaScript có thể bạn đã hoặc chưa từng dùng. Cụ thể như nào thì hãy cùng mình tìm hiểu trong bài viết này nhé (go).

0 0 436

- vừa được xem lúc

Một số phương thức với object trong Javascript

Trong Javascript có hỗ trợ các loại dữ liệu cơ bản là giống với hầu hết những ngôn ngữ lập trình khác. Bài viết này mình sẽ giới thiệu về Object và một số phương thức thường dùng với nó.

0 0 158

- vừa được xem lúc

Tìm hiểu về thư viện axios

Giới thiệu. Axios là gì? Axios là một thư viện HTTP Client dựa trên Promise.

0 0 149

- vừa được xem lúc

Imports và Exports trong JavaScript ES6

. Giới thiệu. ES6 cung cấp cho chúng ta import (nhập), export (xuất) các functions, biến từ module này sang module khác và sử dụng nó trong các file khác.

0 0 113

- vừa được xem lúc

Bài toán đọc số thành chữ (phần 2) - Hoàn chỉnh chương trình dưới 100 dòng code

Tiếp tục bài viết còn dang dở ở phần trước Phân tích bài toán đọc số thành chữ (phần 1) - Phân tích đề và những mảnh ghép đầu tiên. Bạn nào chưa đọc thì có thể xem ở link trên trước nhé.

0 0 249