• בלוג
  • טיפ JavaScript: טיפול באוביקט או Promise מאותה פונקציה

טיפ JavaScript: טיפול באוביקט או Promise מאותה פונקציה

09/09/2021

הטריק הבא לא מסובך למימוש אבל יכול לחסוך לכם קצת if-ים כשאתם זוכרים להשתמש בו במקומות הנכונים. בואו נניח שיש לי פונקציה שצריכה להפוך את האות הראשונה בכל מילה לאותיות גדולות, משהו כזה:

function capitalize(item) {
  return item.replace(/\b(\w)/g, c => c.toUpperCase());
}

ופתאום מגיע חבר שרוצה להשתמש בה במקום נוסף במערכת - אבל אין לו ביד מחרוזת טקסט אלא Promise למחרוזת. האינטואיציה הראשונה היא להתעצבן על החבר או לבקש ממנו להוסיף await בכל מקום, אבל אם נעצור לחשוב על זה לרגע נראה שיש פיתרון הרבה יותר פשוט. כל מה שצריך הוא לעדכן את הפונקציה שלנו שתדע להתמודד עם קלטים מכל מיני סוגים:

function capitalize(itemOrPromise) {
  if (itemOrPromise.then) {
    return itemOrPromise.then(capitalize);
  }

  // Now we know it's an item
  return itemOrPromise.replace(/\b(\w)/g, c => c.toUpperCase());
}

אם היא קיבלה Promise (כלומר משהו שיש לו then) היא תתלבש על ה then ותישאר באותו הממשק כך שתחזיר גם Promise. אם היא קיבלה מחרוזת טקסט עדיין הכל טוב והיא תחזיר את המחרוזת המעודכנת.

ומי שבכלל רוצה להתחשב יכול להוסיף גם טיפול במערכים ועל הדרך במערכים של Promises:

function capitalize(itemOrPromise) {
  if (Array.isArray(itemOrPromise)) {
    return itemOrPromise.map(capitalize);
  }

  if (itemOrPromise.then) {
    return itemOrPromise.then(capitalize);
  }

  // Now we know it's an item
  return itemOrPromise.replace(/\b(\w)/g, c => c.toUpperCase());
}

אם קיבלנו מערך נריץ map כדי להפוך לאותיות גדולות את כל התאים שלו (ואם התאים הם Promises הכל עדיין יעבוד); אם קיבלנו Promise אז נחכה שהוא יסתיים, ואז הרקורסיה תטפל גם במקרה שקיבלנו Promise למערך וכשמגיעים בסוף למחרוזת טקסט אפשר לסיים ולהפוך את האות הראשונה בכל מילה לאות גדולה.

אגב JavaScript והכל, אז אין גם בעיה להוציא החוצה את כל הלוגיקה הרקורסיבית כדי שיהיה קל להשתמש בה על כמה פונקציות. זה נראה כך:

function handleAllThenThings(func) {
  return function handler(itemOrPromise) {
    if (Array.isArray(itemOrPromise)) {
      return itemOrPromise.map(handler);
    }

    if (itemOrPromise.then) {
      return itemOrPromise.then(handler);
    }

    // Now we know it's an item
    return func(itemOrPromise);
  };
}