היזהרו מ-lodash.memoize
lodash.memoize נראה כמו ביצועים בחינם. עוטפים פונקציה ומקבלים מטמון (cache).
אבל להתנהגות ברירת המחדל יש מלכודת. היא בונה את מפתח המטמון מהארגומנט הראשון בלבד. היא מתעלמת מכל ארגומנט אחר.
אם אתם משתמשים בארגומנט אחד, אתם בטוחים. אם אתם משתמשים בשניים או יותר, אתם יוצרים באגים.
הסתכלו על הדוגמה הזו:
const add = memoize((a, b) => a + b);
add(1, 2); // מחזיר 3. הוא שומר במטמון את התוצאה תחת המפתח 1.
add(1, 9); // מחזיר 3. זה שגוי. זה אמור להיות 10.
Lodash רואה שוב את 1. הוא מוצא את 1 במטמון. הוא מחזיר את התוצאה הישנה. הוא אפילו לא מסתכל על ה-9.
עיצוב מטבע הוא מלכודת נפוצה.
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 במטמון ומחזירה דולרים במקום אירו. אין שגיאה. אין אזהרה. אתם פשוט מציגים למשתמשים שלכם את הכסף הלא נכון.
עליכם לספק ארגומנט שני כדי להגדיר את מפתח המטמון. מפתח זה חייב לכסות כל קלט.
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