ESC را فشار دهید تا بسته شود

Promise در JavaScript

جاوااسکریپت در ذات خودش یک زبان Synchronous هستش. تفاوت asynchronous و synchronous توی اینه که توی زبان های synchronous مثل جاوااسکریپت شما توی هر لحظه دقیقا یک کار رو می‌تونین انجام بدین و دستورات خط به خط اجرا میشن اما توی asynchronous در هر لحظه شما می‌تونین چندین کار رو انجام بدین و منتظر اجرای خط به خط دستورات نباشین.

JavaScript رو هم میشه به asynchronous تبدیل کرد؟

استفاده از Callbacks, Promises, Async/Await, setTimeout, setInterval, WebWorkers و …

اما چرا ما به asynchronous توی JS نیاز داریم؟

  • وقتی با API کار میکنیم، برای اینکه از عملکرد بقیه برنامه جلوگیری نشه تا API عملیات CRUD رو انجام بده.
  • وقتی که نیازه صبر کنیم تا داده از یک منبع خارجی بارگذاری بشه که عموما این کار هم با API هستش
  • بتونیم چندین عملیات رو بصورت همزمان اجرا کنیم بدون اینکه روی عملکرد کلی برنامه تاثیر بذاره
  • تجربه کاربری بهتری رو به کاربران می‌دین (همش قرار نیست UI باشه)
  • و موارد دیگه ای که شما بهتر از من می‌دونین

که توی این مطلب قراره راجب متدهای Promise و Prototypes حرف بزنیم.

Promise Object نشون میده که نتجه یک عملیات asynchronous آیا موفق بوده و یا شکست خورده که در یکی از این سه حالت هستش:

  • pending : حالت اولیه است و هنوز معلوم نیست که قراره عملیات با موفقیت انجام بشه یا نه
  • fulfilled : عملیات با موفقیت انجام شد
  • rejected : عملیات با خطا مواجه شد
states of promises
منبع تصویر MDN

Promise Methods

Promise ها متدهای مختلفی دارن که برای مدیریت کردن درخواست های مختلف به ما کمک می‌کنن که بسته به عملکرد و اون خواسته ای که توی کد ازش داریم می‌تونیم از این متدها استفاده کنیم که خب بریم بررسی‌شون کنیم

۱. Promise.all

این متد آرایه ای از promise ها رو می‌گیره و توی خروجی هم به ما promise برمی‌گردونه.

ما تمام promise هارو توی آرایه بهش پاس می‌دیم اگر همه promise ها نتیجه‌شون fulfilled بشه پس خروجی نهایی Promise.all هم fulfill میشه اما اگر فقط یکی از promise هایی که بهش پاس دادیم reject بشه نتیجه Promise.all هم reject میشه

نمونه از Promise.all اگر تمامی promise های داده شده با موفقیت به پایان برسن :

let function1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Resolve Function 1"), 1000);
});
let function2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Resolve Function 2"), 2000);
});
let function3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Resolve Function 3"), 3000);
});

Promise.all([function1, function2, function3])
  .then((response) => console.log("fulfilled",response))
  .catch((error) => console.log("rejected", error));

خروجی این کد به شکل زیر میشه :

اما اگر فقط یکی از عملیات ها با خطا مواجه بشه نتیجه نهایی هم rejected میشه که کد زیر رو بررسی کنیم که ما روی function2 از reject توی تابع استفاده کردیم :

let function1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Resolve Function 1"), 1000);
});
let function2 = new Promise((resolve, reject) => {
    // Change is here 👇
  setTimeout(() => reject("Reject Function 2"), 2000);
});
let function3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Resolve Function 3"), 3000);
});

Promise.all([function1, function2, function3])
  .then((response) => console.log("fulfilled",response))
  .catch((error) => console.log("rejected", error));

و نتیجه نهایی اون میشه :

۲. Promise.allSettled

متد allSettled هم مثل Promise.all کار می‌کنه اما برخلاف Promise.all اگر یکی از عملیات ها rejected شد نتیجه نهایی rejected نمیشه و منتظر اجرای همه می‌مونه و تمام نتایج رو توی یه آرایه به ما برمیگردونه

کد زیر رو بررسی کنیم:

let function1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Resolve Function 1"), 1000);
});
let function2 = new Promise((resolve, reject) => {
    // Reject is here 👇
  setTimeout(() => reject("Reject Function 2"), 2000);
});
let function3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Resolve Function 3"), 3000);
});

Promise.allSettled([function1, function2, function3])
  .then((response) => console.log(response))

توی کد بالا توابع ۱ و ۳ با موفقیت انجام میشن اما تابع ۲ قراره ناموفق باشه خروجی نهایی :

۳. Promise.race

مثل allSettled عمل می‌کنه اما تفاوتی که داره فقط یک خروجی به ما میده. چندین promise بهش بعنوان ورودی می‌دیم و وضعیت اولین promise رو بعنوان خروجی ست میکنه کد زیر رو ببینیم :

let function1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Resolve Function 1"), 1000);
});
let function2 = new Promise((resolve, reject) => {
  setTimeout(() => reject("Reject Function 2"), 2000);
});
let function3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Resolve Function 3"), 3000);
});

Promise.race([function1, function2, function3])
  .then((response) => console.log("fulfilled", response))
  .catch((error) => console.log("rejected", error));

توی کد بالا به function1 زمان 1000ms دادیم پس زودتر از بقیه به نتیجه و به اتمام می‌رسه، متد race براش مهم نیست که function1 قراره نتیجه اش rejected یا fulfilled بشه فقط چون سریعتر به نتیجه می‌رسه پس بعنوان خروجی نهایی Promise.race در نظر گرفته میشه. نتیجه زیر:

۴. Promise.any

چند تابع promise رو بعنوان ورودی می‌گیره و فقط یک خروجی میده و خروجی هم اولین تابع promise هستش که نتیجه اش fulfilled میشه.

پس در چه صورت rejected برمی‌گردونه؟ فقط و فقط زمانی که نتیجه تمام promise های داده شده rejected بشه اونوقت تابع نهایی Promise.any هم rejected میشه در غیر این صورت همیشه اولین promise که نتیجه اش fulfilled بشه رو برمیگردونه

let function1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Resolve Function 1"), 1000);
});
let function2 = new Promise((resolve, reject) => {
  setTimeout(() => reject("Reject Function 2"), 2000);
});
let function3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Resolve Function 3"), 500);
});

Promise.any([function1, function2, function3])
  .then((response) => console.log("fulfilled", response))
  .catch((error) => console.log("rejected", error));

توی توابع بالا function3 مقدار 500ms داره و سریعتر از بقیه توابع به نتیجه fulfilled میرسه پس تابع نهایی هم فقط یک خروجی داره و مقدار اون هم باید مقدار function3 باشه:

اما حالتی به ما rejected برمی‌گردونه که تمامی توابع نتیجه نهایشون rejected بشه:

let function1 = new Promise((resolve, reject) => {
  setTimeout(() => reject("Resolve Function 1"), 1000);
});
let function2 = new Promise((resolve, reject) => {
  setTimeout(() => reject("Reject Function 2"), 2000);
});
let function3 = new Promise((resolve, reject) => {
  setTimeout(() => reject("Resolve Function 3"), 500);
});

Promise.any([function1, function2, function3])
  .then((response) => console.log("fulfilled", response))
  .catch((error) => console.log("rejected ❌", error));

نتیجه نهایی :

۵. (value)Promise.resolve

یک promise می‌سازه که همیشه نتیجه مقدار اون بعنوان fulfilled به ما می‌رسه

const promiseResolved = Promise.resolve("Hello World")

promiseResolved.then(value => console.log(value))

//OUTPUT
// Hello World

۶. (error)Promise.reject

یک promise می‌سازه که همیشه نتیجه مقدار اون بعنوان rejected به ما می‌رسه

const promiseResolved = Promise.reject("Error Rejected")

promiseResolved.catch(err => console.log(err))

//OUTPUT
// Error Rejected

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *