promise چیست و چه کاربردی دارد؟ (ری اکت)

23 فروردین 1398
درسنامه درس 14 از سری آموزش react (ری اکت)
React-promise

Promise چیست؟

طبق تعریف موزیلا، آبجکت promise برای مدیریت محاسبات غیرهمزمان در مواقعی که مدیریت محاسبات توسط متدهای کالبک مشکل باشد، استفاده می شود.

Promise ها متدهایی را برای کنترل مقادیر، در حین انجام موفقیت آمیز یا غیرموفقیت آمیز یک عملیات، ارائه می کنند.

Promise با ما این امکان را می دهد تا در مواقع موفقیت یا شکست یک عملیات غیرهمزمان، یک قابلیتی را به اجرا در آوریم. همچنین این اجازه را می دهد تا این گونه سناریوهای پیچیده را با کدهای معمولی (همزمانی) پیاده سازی کنیم.

برای مثال، به کدهای همزمانی زیر که مقدار زمان جاری را در خروجی چاپ می کند، توجه کنید:

var currentTime = new Date();
console.log('The current time is: ' + currentTime);

کدهای فوق خیلی سرراست است و مقدار آبجکت ()new Date که زمان جاری است را در مرورگر نشان می دهد. حال فرض کنید که ما از ساعت های مختلف بر روی تعدادی از سرورهای از راه دور استفاده می کنیم.

برای مثال، اگر یک ساعت تبریک سال نو را در نظر بگیرید، خیلی خوب است که بتوانیم مرورگر کاربران را با یکدیگر با استفاده از یک مقدار زمانی واحد، همگام کنیم.

فرض کنید متدی به نام ()getCurrnetTime داریم که مقدار زمان جاری را از یک سرور از راه دور دریافت می کند. سپس توسط متد ()setTimeOut این متد را بعد از 2 ثانیه اجرا می کنیم (در حقیقت با اینکار دریافت داده ها از یک API را شبیه سازی می کنیم).

function getCurrentTime() {
  // Get the current 'global' time from an API
  return setTimeout(function() {
    return new Date();
  }, 2000);
}
var currentTime = getCurrentTime()
console.log('The current time is: ' + currentTime);

مقداری که console.log نشان می دهد، قطعاً زمان جاری نیست. معمولا توسط یک کالبک مقدار زمان را بروزرسانی می کنیم:

function getCurrentTime(callback) {
  // Get the current 'global' time from an API
  return setTimeout(function() {
    var currentTime = new Date();
    callback(currentTime);
  }, 2000);
}
getCurrentTime(function(currentTime) {
  console.log('The current time is: ' + currentTime);
});

اما اگر خطایی در حین عملیات اتفاق بیفتد، باید چکار کنیم؟ چطور باید خطا را مدیریت کنیم؟

function getCurrentTime(onSuccess, onFail) {
  // Get the current 'global' time from an API
  return setTimeout(function() {
    // randomly decide if the date is retrieved or not
    var didSucceed = Math.random() >= 0.5;
    if (didSucceed) {
      var currentTime = new Date();
      onSuccess(currentTime);
    } else {
      onFail('Unknown error');
    }
  }, 2000);
}
getCurrentTime(function(currentTime) {
  console.log('The current time is: ' + currentTime);
}, function(error) {
  console.log('There was an error fetching the time');
});

حال، اگر بخواهیم یک درخواست بر اساس مقدار اولین درخواست ایجاد کنیم، باید چکار کنیم؟

به عنوان مثال، اجازه بدهید دوباره از متد ()getCurrentTime مطابق زیر استفاده کنیم:

function getCurrentTime(onSuccess, onFail) {
  // Get the current 'global' time from an API
  return setTimeout(function() {
    // randomly decide if the date is retrieved or not
    var didSucceed = Math.random() >= 0.5;
    console.log(didSucceed);
    if (didSucceed) {
      var currentTime = new Date();
      onSuccess(currentTime);
    } else {
      onFail('Unknown error');
    }
  }, 2000);
}
getCurrentTime(function(currentTime) {
  getCurrentTime(function(newCurrentTime) {
    console.log('The real current time is: ' + currentTime);
  }, function(nestedError) {
    console.log('There was an error fetching the second time');
  })
}, function(error) {
  console.log('There was an error fetching the time');
});

در این روش، کار کردن با عملیات غیرهمزمان کمی دشوار است. همچنین می توانیم مقادیر را از فراخوانی تابع قبلی بدست بیاوریم. گاهی اوقات به مسائلی برخورد می کنیم که هنگام شروع برنامه هنوز بعضی از داده ها دریافت نشده اند.

کار کردن با promise

با استفاده از promise ها می توانیم بر بسیاری از پیچیدگی های فوق غلبه کنیم. برای مثال می توان کدهای بالا را توسط promise مطابق زیر بازنویسی کرد:

function getCurrentTime(onSuccess, onFail) {
  // Get the current 'global' time from an API using Promise
  return new Promise((resolve, reject) => {
    setTimeout(function() {
      var didSucceed = Math.random() >= 0.5;
      didSucceed ? resolve(new Date()) : reject('Error');
    }, 2000);
  })
}
getCurrentTime()
  .then(currentTime => getCurrentTime())
  .then(currentTime => {
    console.log('The current time is: ' + currentTime);
    return true;
  })
  .catch(err => console.log('There was an error:' + err))

همان طور که می بینید کدهای فوق تمیزتر به نظر می رسد و همچنین مشکلاتی که در هنگام کار با عملیات غیرهمزمان به وجود می آید را ندارد. در صورت موفقیت آمیز بودن عملیات از تابع ()then بر روی یک نمونه از آبجکت promise استفاده می کنیم. همچنین برای دسترسی به مقدار برگشتی promise از متد ()then استفاده می کنیم. برای نمونه در مثال فوق، مقدار تابع ()getCurrentTime در currentTime قرار گرفته و در صورت موفقیت آمیز بودن عملیات، آن مقدار در خروجی چاپ می شود. برای کنترل خطاهای احتمالی که ممکن است در این زنجیره promise اتفاق بیفتد، از متد ()catch استفاده می شود.

در مثال بالا از یک زنجیره promise برای ساخت دنباله ای از کارها که یکی پس از دیگری باید اجرا شود، استفاده کردیم. در نگاه اول promise کمی پیچیده به نظر می رسد، اما در حقیقت کار با آنها خیلی راحت است.همچنین در صورت موفقیت آمیز بودن یک عملیات می توانیم از کدهای معمولی برای کنترل کارهای غیرهمزمان استفاده کنیم.

برای مثال اگر بخواهیم مقدار برگشتی فراخوانی تابع ()getCurrentTime را تغییر دهیم، می توانیم مانند زیر یک ارتباط بین زنجیرها برقرار کنیم:

getCurrentTime()
  .then(currentTime => getCurrentTime())
  .then(currentTime => {
    return 'It is now: ' + currentTime;
  })
  // this logs: "It is now: [current time]"
  .then(currentTimeMessage => console.log(currentTimeMessage))
  .catch(err => console.log('There was an error:' + err))

حالت های مختلف یک promise

یک promise در یک زمان تنها می تواند یکی از حالت های زیر را داشته باشد:

  • معلق (pending)
  • انجام شده (resolved)
  • رد شده (error)

یک آبجکت معلق (Pending) می تواند در یکی از حالت های انجام شده (resolved) یا رد شده (error) و تنها یکبار اتفاق بیفتد و در بعضی از مواقع که ممکن است خطاهای پیچیده در برنامه اتفاق بیفتد، کاربرد دارد. در این شرایط، هر حالت که اتفاق بیفتد یک promise را بر می گردانیم. اگر بخواهیم مقداری را از تابعی که از promise استفاده می کند را برگردانیم، باید promise جدیدی را ایجاد کنیم.

ساخت یک promise

با استفاده از متد سازنده promise می توانیم یک promise جدید ایجاد کنیم. این متد سازنده یک تابع با دو پارامتر می گیرد، که عبارتند از:

  • onSuccess : برای کنترل حالت موفقیت آمیز بودن عملیات استفاده می شود
  • onFail: برای کنترل حالتی که یک عملیات با شکست مواجه گردد، استفاده می شود

در مثال بالا، اگر درخواست با موفقیت اجرا شود متد ()resolve و اگر با خطا مواجه شود متد ()reject اجرا می شود.

var promise = new Promise(function(resolve, reject) {
  // call resolve if the method succeeds
  resolve(true);
})
promise.then(bool => console.log('Bool is true'))

حال که فهیدیم promise چیست و چطور کار می کند، می توانیم از کتابخانه fetch که در درس بعدی ارائه خواهیم داد، استفاده کنیم.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش react (ری اکت) توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما (1 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

سبحان
22 مهر 1398
سلام پارسال مقاله انگولار سایتتون رو خوندم نکته ای که میخوام بگم اینه خیلی اصولی وکامل فریمورک یا .. رو معرفی کردید و وارد جزیات نشدید به نظرم اصلش همینه چهارچوب رو بلد باشی میتونی سرچ بزنی ب جواب برسی مقاله ری اکت تون هم دقیقا هم سبک رو داره و بنظر خیلی خیلی مفید تر از یک فیلم اموزشه من شخصا اصلا اموزش های فارسی رو نمیبینم بجز چند سایت با تشکر

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.