مراقب lodash.memoize باشید
به نظر میرسد lodash.memoize عملکرد (performance) رایگان به شما هدیه میدهد. شما یک تابع را wrap میکنید و یک cache دریافت میکنید.
اما رفتار پیشفرض آن یک تله دارد. این تابع کلید کش (cache key) را فقط از اولین آرگومان میسازد و سایر آرگومانها را نادیده میگیرد.
اگر از یک آرگومان استفاده کنید، در امان هستید. اما اگر از دو یا چند آرگومان استفاده کنید، باگ ایجاد خواهید کرد.
به این مثال نگاه کنید:
const add = memoize((a, b) => a + b);
add(1, 2); // مقدار 3 را برمیگرداند. نتیجه را با کلید 1 کش میکند. add(1, 9); // مقدار 3 را برمیگرداند. این اشتباه است. باید 10 باشد.
Lodash دوباره عدد 1 را میبیند. عدد 1 را در کش پیدا میکند و نتیجه قدیمی را برمیگرداند. اصلاً به عدد 9 نگاه نمیکند.
فرمتبندی واحد پول (Currency formatting) یک تله رایج است.
const formatPrice = memoize((amount, currency) => new Intl.NumberFormat('en', { style: 'currency', currency }).format(amount) );
formatPrice(100, 'USD'); // مقدار "$100.00" را برمیگرداند. کلید برابر با 100 است. formatPrice(100, 'EUR'); // مقدار "$100.00" را برمیگرداند. این اشتباه است.
فراخوانی دوم، 'EUR' را نادیده میگیرد. عدد 100 را در کش میبیند و به جای یورو، دلار برمیگرداند. هیچ خطایی رخ نمیدهد. هیچ هشداری داده نمیشود. شما فقط مبلغ اشتباه را به کاربران خود نشان میدهید.
شما باید آرگومان دومی را برای تعریف کلید کش (cache key) ارائه دهید. این کلید باید تمام ورودیها را پوشش دهد.
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"
کلید باید هر چیزی را که باعث تغییر خروجی میشود، شامل شود.
یک نکته پایانی: استفاده از memoization ریسک را افزایش میدهد. فقط زمانی از آن استفاده کنید که یک تابع سنگین (expensive) باشد و مکرراً با ورودیهای یکسان اجرا شود. برای توابع ساده، فقط آنها را فراخوانی کنید. ریسک ایجاد یک باگ اغلب بیشتر از سرعتی است که به دست میآورید.
نکات کلیدی:
- کلیدهای پیشفرض فقط از اولین آرگومان استفاده میکنند.
- از یک resolver استفاده کنید تا تمام آرگومانها در کلید گنجانده شوند.
- یک کلید خوب باید بازتابدهنده هر چیزی باشد که خروجی را تغییر میدهد.
- از memoize برای توابع سبک (cheap) استفاده نکنید.
منبع: https://dev.to/figsify/beware-of-lodashmemoize-it-only-remembers-the-first-argument-4cjl