Hãy cẩn thận với lodash.memoize
Lodash memoize trông có vẻ như là một cách tăng hiệu năng miễn phí. Bạn chỉ cần bọc một hàm lại và sẽ có ngay một bộ nhớ đệm (cache).
Nhưng hành vi mặc định của nó ẩn chứa một cái bẫy. Nó chỉ xây dựng khóa cache (cache key) từ đối số đầu tiên. Nó bỏ qua tất cả các đối số khác.
Nếu bạn chỉ sử dụng một đối số, bạn sẽ an toàn. Nếu bạn sử dụng từ hai đối số trở lên, bạn đang tạo ra lỗi (bugs).
Hãy nhìn vào ví dụ này:
const add = memoize((a, b) => a + b);
add(1, 2); // Trả về 3. Nó lưu kết quả vào cache với khóa là 1.
add(1, 9); // Trả về 3. Điều này là sai. Đáng lẽ phải là 10.
Lodash lại thấy số 1. Nó tìm thấy số 1 trong cache. Nó trả về kết quả cũ. Nó không hề xem xét đến số 9.
Định dạng tiền tệ là một cái bẫy phổ biến.
const formatPrice = memoize((amount, currency) =>
new Intl.NumberFormat('en', { style: 'currency', currency }).format(amount)
);
formatPrice(100, 'USD'); // Trả về "$100.00". Khóa là 100.
formatPrice(100, 'EUR'); // Trả về "$100.00". Điều này là sai.
Lần gọi thứ hai đã bỏ qua 'EUR'. Nó thấy 100 trong cache và trả về đô la thay vì euro. Không có lỗi xảy ra. Cũng không có cảnh báo nào. Bạn chỉ đơn giản là hiển thị sai loại tiền tệ cho người dùng của mình.
Bạn phải cung cấp một đối số thứ hai để định nghĩa khóa cache. Khóa này phải bao quát tất cả các đầu vào.
const formatPrice = memoize(
(amount, currency) =>
new Intl.NumberFormat('en', { style: 'currency', currency }).format(amount),
(amount, currency) => `${amount}|${currency}`
);
formatPrice(100, 'USD'); // "$100.00"
formatPrice(100, 'EUR'); // "€100.00"
Khóa phải nắm bắt được tất cả những gì làm thay đổi kết quả đầu ra.
Một suy nghĩ cuối cùng: memoization làm tăng rủi ro. Chỉ sử dụng nó khi một hàm tốn nhiều chi phí tính toán (expensive) và thường xuyên chạy với cùng một đầu vào. Đối với các hàm đơn giản, hãy cứ gọi chúng bình thường. Rủi ro gặp lỗi thường cao hơn lợi ích về tốc độ mà bạn nhận được.
Những điểm chính cần lưu ý:
- Các khóa mặc định chỉ sử dụng đối số đầu tiên.
- Sử dụng một resolver để đưa tất cả các đối số vào khóa.
- Một khóa tốt phải phản ánh được mọi thứ làm thay đổi kết quả đầu ra.
- Đừng sử dụng memoize cho các hàm nhẹ (cheap functions).
Nguồn: https://dev.to/figsify/beware-of-lodashmemoize-it-only-remembers-the-first-argument-4cjl