در جاوااسکریپت چهار ابزار ترکیبی برای اجرای همزمان (Concurrent) عملیاتهای ناهمگام وجود دارد:
Promise.all()
Promise.allSettled()
Promise.any()
Promise.race()
به عنوان مثال، ما میتوانیم چند عملیات را دقیقاً در یک زمان با هم استارت بزنیم و منتظر بمانیم تا همهی آنها به پایان برسند:
Promise.all([func1(), func2(), func3()]).then(([result1, result2, result3]) => {
// استفاده از result1، result2 و result3
});
نکته مهم در مورد Promise.all() این است که اگر حتی یکی از پرامیسهای داخل آرایه رد (Reject) شود، کل خروجی متد Promise.all() فوراً رد میشود. در این حالت، بقیه عملیاتها در پسزمینه به کار خودشان ادامه میدهند، اما نتیجه آنها دیگر از طریق مقدار بازگشتی Promise.all() در دسترس نخواهد بود. این اتفاق ممکن است باعث ایجاد وضعیت یا رفتارهای غیرمنتظره در برنامه شما شود.
برای حل این مشکل، ابزار ترکیبی دیگری به نام Promise.allSettled() وجود دارد که به شما اطمینان میدهد تکتک عملیاتها کاملاً تعیین تکلیف شده و به پایان برسند (چه با موفقیت و چه با خطا) و سپس نتیجه را برمیگرداند.
تمام این متدها، پرامیسها را به صورت همزمان اجرا میکنند؛ یعنی مجموعهای از پرامیسها همزمان شروع میشوند و منتظر یکدیگر نمیمانند.
اگر بخواهید پرامیسها را پشت سر هم و به ترتیب اجرا کنید، میتوانید با استفاده از ترفندهای هوشمندانه جاوااسکریپت این کار را انجام دهید:
[func1, func2, func3]
.reduce((p, f) => p.then(f), Promise.resolve())
.then((result3) => {
/* استفاده از result3 */
});
در این مثال، ما یک آرایه از توابع ناهمگام را به کمک متد reduce کاهش داده و به یک زنجیره پرامیس تبدیل کردهایم. کد بالا دقیقاً معادل کد زیر است:
Promise.resolve()
.then(func1)
.then(func2)
.then(func3)
.then((result3) => {
/* استفاده از result3 */
});
شما میتوانید این منطق را به یک تابع ترکیبی قابل استفاده مجدد (Reusable Compose Function) تبدیل کنید، چیزی که در برنامهنویسی تابعی (Functional Programming) بسیار رایج است:
const applyAsync = (acc, val) => acc.then(val);
const composeAsync =
(...funcs) =>
(x) =>
funcs.reduce(applyAsync, Promise.resolve(x));
تابع composeAsync() هر تعدادی از توابع را به عنوان آرگومان ورودی میپذیرد و یک تابع جدید برمیگرداند. این تابع جدید، یک مقدار اولیه را میگیرد و آن را از میان خط لوله ترکیبی (Composition Pipeline) عبور میدهد:
const transformData = composeAsync(func1, func2, func3);
const result3 = transformData(data);
ترکیب توالی را میتوان خیلی خلاصهتر و راحتتر به کمک ساختار async/await نیز انجام داد:
let result;
for (const f of [func1, func2, func3]) {
result = await f(result);
}
/* استفاده از آخرین نتیجه (یعنی همان result3) */
⚠️ یک توصیه مهم: قبل از اینکه پرامیسها را به صورت توالی و پشت سر هم بچینید، حتماً بررسی کنید که آیا واقعاً انجام این کار لازم است یا خیر. همیشه بهتر است پرامیسها را به صورت همزمان اجرا کنید تا بیپایه و اساس جلوی سرعت یکدیگر را نگیرند؛ مگر اینکه اجرای یک پرامیس واقعاً به نتیجه پرامیس قبلی وابسته باشد.
خودِ ساختار ابزار Promise در جاوااسکریپت، به طور پیشفرض پروتکل درجهیکی برای لغو کردن (Cancel) عملیات ندارد؛ اما شما میتوانید عملیات ناهمگامِ زیرین و اصلی را به طور مستقیم لغو کنید، که این کار معمولاً به کمک ابزار AbortController انجام میشود.
مستندات پرامیسها در اینجا به پایان رسید. اگر بخش جدیدی از مستندات (مثل موضوعات دیگر جاوااسکریپت یا وب) مد نظرتان هست، بفرستید تا با همین فرمون جلو ببریم!
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://developer.mozilla.org/en-US/docs/Web/JavaScript