Promise.any

מתודה חדשה ל-Promise מאפשרת ניהול יותר טוב של פרומיסים מרובים.

אחת התוספות הממש חביבות ב-ES2021 הוא ה-any. מתודה שמגיעה עם הפרומיס שבו אנו משתמשים בתכנות אסינכרוני (לא מכירים? זה הזמן! הנה המאמר שלי עליו שכתבתי בתקופה הפרהיסטורית של 2016, אל תשכחו גם את ה-async await!).

אז הנה promise והנה השימוש הבסיסי בו:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 1'), Math.floor(Math.random() * 1000));
});
p1.then(res => console.log(res)); // Promise 1

אנו כמובן יכולים להשתמש ב-async await כדי להשתמש בפרומיס:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 1'), Math.floor(Math.random() * 1000));
});

async function callPromise() {
  const res = await p1;
  console.log(res);
};
callPromise(); // Promise 1

כיוון ש-async await זו הדרך המודרנית, אני אשתמש בה בהמשך המאמר. אני רק מזכיר שמדובר בפיצ'ר של ES2017 אז אם אתם לא מכירים, זו ההזדמנות להכיר.

טוב, הכל מעולה, אבל מה קורה אם יש לנו כמה פרומיסים? איך אני מנהל אותם? אני יכול לקרוא לאחד אחרי השני.

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 1'), Math.floor(Math.random() * 1000));
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 2'), Math.floor(Math.random() * 1000));
});
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 3'), Math.floor(Math.random() * 1000));
});

async function callPromise() {
  let res = await p1;
  console.log(res);
  res = await p2;
  console.log(res);
  res = await p3;
  console.log(res);
};
callPromise(); // Promise 1, Promise 2, Promise 3

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

אם אני רוצה שכולן יצאו בבת אחת אני אשתמש ב-all. כך:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 1'), Math.floor(Math.random() * 1000));
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 2'), Math.floor(Math.random() * 1000));
});
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 3'), Math.floor(Math.random() * 1000));
});

async function callPromise() {
  let res = await Promise.all([p1,p2,p3]);
  console.log(res);
};
callPromise(); // ["Promise 1", "Promise 2", "Promise 3"]

זה מנוהל יותר טוב, אבל אם פרומיס אחד נכשל? הכל נכשל. לא נקבל תוצאה אחת אפילו אלא error. זה יכול להיות סבבה אם אני רוצה שכולן יצליחו. אבל מה אם אני רוצה שכל הפרומיסים יישלחו ואני לא רוצה שגיאה אם הם ייכשלו? אז יש לי את allSettled שעליו גם כתבתי בעבר – הוא יצא בשנה הקודמת:

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 1'), Math.floor(Math.random() * 1000));
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 2'), Math.floor(Math.random() * 1000));
});
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 3'), Math.floor(Math.random() * 1000));
});

async function callPromise() {
  let res = await Promise.allSettled([p1,p2,p3]);
  console.log(res);
};
callPromise(); 
/*
[{status: "fulfilled", value: "Promise 1"},
{status: "fulfilled", value: "Promise 2"},
{status: "fulfilled", value: "Promise 3"},
*/

יש לנו גם את race. שהוא מחזיר את הפרומיס שחזרה הכי מהר בלי קשר להצלחה או לכשלון – מה זאת אומרת? זה אומרת שאם פרומיס אחד עושה reject, אנו מקבלים error.

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 1'), Math.floor(Math.random() * 1000));
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 2'), Math.floor(Math.random() * 1000));
});
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 3'), Math.floor(Math.random() * 1000));
});

async function callPromise() {
  let res = await Promise.race([p1,p2,p3]);
  console.log(res);
};
callPromise(); // Maybe 1, 2 or 3

וזה? זה יכול לבאס מאוד. כי אם אני רוצה את הפרומיס הראשון שמצליח – לא זה שמחזיר לי תשובה, זה עלול להיות סופר בעייתי. בדיוק בשביל זה יש לי את any. הוא עובד בול כמו race, אבל רק על פרומיסים שמצליחים!

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 1'), Math.floor(Math.random() * 1000));
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 2'), Math.floor(Math.random() * 1000));
});
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 3'), Math.floor(Math.random() * 1000));
});

async function callPromise() {
  let res = await Promise.any([p1,p2,p3]);
  console.log(res);
};
callPromise(); // Maybe 1, 2 or 3

אם יש אחד שייכשל? ה-any לא יזרוק שגיאה, הוא פשוט יתעלם ויחכה לפרומיס הבא שיצליח.

const p1 = new Promise((resolve, reject) => reject('Promise 1 fail'));
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 2'), Math.floor(Math.random() * 1000));
});
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 3'), Math.floor(Math.random() * 1000));
});

async function callPromise() {
  let res = await Promise.any([p1,p2,p3]);
  console.log(res);
};
callPromise(); // Maybe 2 or 3, never 1!

ומה קורה עם כולם נכשלים? אז פה יש לנו שגיאה.

const p1 = new Promise((resolve, reject) => reject('Promise 1 fail'));
const p2 = new Promise((resolve, reject) => reject('Promise 2 fail'));
const p3 = new Promise((resolve, reject) => reject('Promise 3 fail'));

async function callPromise() {
  try {
    let res = await Promise.any([p1,p2,p3]);
    console.log(res);
  } catch(e) {
    console.log(e); 
  }
};

callPromise(); // AggregateError: All promises were rejected

מדובר בעוד כלי בארסנל של הפרומיסים שמאפשר לנהל פרומיסים מרובים בהתאם לצורך ומאפשר גמישות גדולה עם קוד אלגנטי. יופי של תוספת ל-2021.

פוסטים נוספים שכדאי לקרוא

פתרונות ומאמרים על פיתוח אינטרנט

המנעו מהעלאת source control לשרת פומבי

לא תאמינו כמה אתרים מעלים את ה-source control שלהם לשרת. ככה תמצאו אותם וגם הסבר למה זה רעיון רע.

ESP32 מאפס לילדים

מדריך ל-ESP32 לילדים ולהורים מאפס

אחד הדברים הכי כיפיים בעולם הוא תכנות ותכנות בעולם האמיתי – המפעיל אורות, ציוד אלקטרוני ומכשירים הוא מלהיב ממש. המדריך מיועד להורים שרוצים ללמד את הילדים שלהם לתכנת.

גלילה לראש העמוד