استفاده async/await در حلقه map جاوااسکریپت

سلام دوستان خوبم وقتتون بخیر ? . شاید بعضی وقتا براتون این اتفاق افتاده باشه که Dataیی رو دارید از یه Api میگیرید و برای اینکه روی اون Data تغییراتی انجام بدید باید روی اون map بزنید و توی این mapی که دارید میزنید هر loop که بخواد اجرا بشه باید loop قبلیش تکمیل شده باشه . در حالت معمول که بخواین از map استفاده کنین به یکسری مشکل میخورید ? ولی اگه به حرف من گوش کنین به مشکل نمیخورین ? پس با من همراه باشین.async/await در حلقه mapشبیه سازی Apiدر مرحله اول من اینجا یه تابع دارم که در واقع اومده همون Api مورد نظرمون رو که میخوایم روش map بزنیم رو شبیه سازی کرده که همانطور که در پایین می بینید ما یک آرایه از نام های کاربری و یک تابع داریم که یک پارامتر را می گیره و یک رشته را برمی گردونه.const usernames: string[] = [&quotjordanrjdev&quot, &quotanonymous123&quot, &quotchannelyy&quot]; const simulateFetchData = (username: string): Promise<string> => { return new Promise((resolve) => { setTimeout(() => { resolve(`${username} is a valid username`); }, 1000); }); }حالا میخوایم آرایه نام کاربری را تکرار کنیم تا داده های شبیه سازی شده هر کاربر رو با map بدست بیاریم.const dataUsers = usernames.map(async (username) => { return await simulateFetchData(username); }); console.log(dataUsers);حالا بریم با هم log مون رو ببینیم تا ببینیم خروجی چیه ![ Promise { <pending> }, Promise { <pending> }, Promise { <pending> } ] بله همونطور که مشاهده میکنید خروجی چیزی جز Promise های pending نیست که داره بهمون نشون میدهاین هم بخاطر ماهیت async/await هست که از Promise استفاده میکنه و اینطور هست که توی هر گام از حلقه map مون صبر نمیکنه تا نتیجه Promise برگرده به همین خاطر همه گام های map مون در حالت معلق ( pending ) باقی می مونن.حالا چاره چیه؟?استفاده از For ofراه حل اول استفاده از حلقه for..of هست بریم با هم ببینیم چجوری پیاده سازی میشهconst getWithForOf = async() => { console.time(&quotfor of&quot); const data = []; for (const username of usernames) { let dataUser = await simulateFetchData(username); data.push(dataUser); } console.timeEnd(&quotfor of&quot); } getWithForOf();این راه حل خوبیه و رایج هست ولی مشکلی که داره زمان زیادی رو صرف میکنه تا اون چیزی رو که میخوایم رو بهمون بده ? توی کد دقت کنین از console.time استفاده کردم تا ببینید زمانی که صرف میشه چقد هست که خروجی که بهمون نشون میده به نظرم فاجعه س ? چون حالا این یه تابع ساده بیشتر نیست که انقد زمان صرفش کرده، واسه Data ی واقعی میخواد چیکار کنه ! ?for of: 3.012sاستفاده از Promise.allراه حل دیگه ای که خودمم اون رو پیشنهاد میدم (حالا بازم بستگی به شرایط داره) استفاده از Promise.all هست، دوستان.const getWithPromiseAll = async() => { console.time(&quotpromise all&quot); let data = await Promise.all(usernames.map(async (username) => { return await simulateFetchData(username); })) console.timeEnd(&quotpromise all&quot); } getWithPromiseAll();خاطرتون هست که بهتون گفتم async/await از Promise استفاده میکنه ! یعنی این کدی که داشتیم usernames.map(async (username) => { return await simulateFetchData(username); })هر گام map مون، بهمون یه Promise برمیگردوند، درسته! حالا ما توی روش دوم اومدیم از Promise.all استفاده کردیم که بیاد تمامی Promise هامون رو نتیجه ش رو بهمون برگردونه ( فقط این نکته حواستون باشه Promise.all ببینه یکی از Promise ها reject شده باشه کل عملیاتش رو reject میکنه ، از بس که بی اعصابه این متد ?) کلا این متد فوق العادس برای زمانی که کدهای Asynchronous دارید و میخواید بصورت موازی همه چی پیش بره.حالا بریم ببینیم خروجی console.time مون چیهpromise all: 980.3000000119209msیعنی این دوستمون کار رو نذاشت به یک ثانیه هم برسه ?? نتیجه گیریهمونطور که من همیشه میگم و الانم میگم بهتون، با قطعیت نمیگم که کدوم روش بهتره ، اگه شرایط Performance رو در نظر بگیریم خب طبیعتاً Promise.all عالیه ولی یه مواقعی ممکنه بخواید از حلقه for استفاده کنید پس اون موقع چاره ای جز این نداریم که از for..of استفاده کنیم . خب دیگه امیدوارم دوستان این مقاله براتون مفید بوده باشه و جا داره اینجا از دوست و همکار خوبم محمدرضا تشکر کنم که باعث شد این مقاله رو بنویسم و همینطور دوستمون Jordan Jaramillo . شب و روز تون خوش مراقب خودتون باشید ?.