معرفی مفاهیم asynchronous, promises, async/await در جاوا اسکریپت

معرفی مفاهیم asynchronous, promises, async/await در جاوا اسکریپت

یکی از مفاهیم نسبتا سخت و پیچیده که بیشتر اوقات باعث گیج شدن و سردرگمی برخی از برنامه نویسان می شود مفهوم غیرهمزمان یا Asynchronous می باشد .

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

این بخش سه قسمت دارد :

  1. asynchronous JS
  2. Promises
  3. async/await


قبل شروع مفاهیم بالا باید این سوال را در ابتدا از خود بپرسیم که چرا ما به برنامه نویسی ناهمزمان اهمیت می دهیم؟

موضوع غیر همزمان بودن در دو بخش سرور و کلاینت مورد اهمیت می باشد ولی در این مقاله بیشتر بر روی کلاینت تمرکز میکنم ولی در اینده حتما برای باز کردن مباحث بیشتر مایلم آن را به بخش سرور ببرم.

ابتدا باید بدانیم که جاوا اسکریپت همیشه همزمان و تک رشته ای است. به عبارت دیگر ، هنگامی که یک بلوک کد اجرا می شود، هیچ بلوک دیگری از کد اجرا نمی شود.

 

همانطور که در بالا مشاهده می کنید کنسول مقادیر را به ترتیب چاپ می کند.

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

ما از JS ناهمزمان در مواردی مانند واکشی یا دسترسی به نوعی منبع از API شخص ثالث استفاده می کنیم.

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

برنامه نویسی ناهمزمان توسط Callback ها

قبل از اینکه وارد Promise ها بشویم اساسی ترین مفهومی که باید بفهمیم فراخوانی می باشد (گذراندن یک تابع دیگر در یک تابع و هنگامی که شرایطی برآورده می شود یا رویدادی رخ می دهد، فراخوانی می شود).

همچنین روش قدیمی مدیریت برنامه نویسی ناهمزمان قبل از معرفی Promise در ES6 است. اما برخی از این callback ها هنوز معمولاً بدون promise دیده می شوند.

 

اولین آرگومان ()setTimeOut یک تابع callback و آرگومان دوم یک فاصله زمانی است که بر حسب میلی ثانیه اندازه گیری می شود.

معرفی Promise ها

Promises در ES6 برای ساده سازی برنامه نویسی ناهمزمان یا نامتقارن معرفی شدند. در این بخش به موارد زیر می پردازیم:

  • چرا promise ها معرفی شدند؟‌ (هشدار خرابکاری:‌ مشکل در فراخوانی و شلوغی callback ها)
  • تمام promise ها به ما قول میدهند که پاسخ را در سه حالت برگرداند : (then, catch, finally)

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

 

chooseCoffee(function(order) {
  placeOrder(order, function(coffee) {
    drinkCoffee(coffee);
  }, failureCallback);
}, failureCallback);

 

ظاهر بسیار کثیفی دارد! این همان چیزی است که اغلب به عنوان callbacks-hell یا جهنم فراخوانی ها‍‍‍ نامیده می شود. promise ها اجازه می دهند این نوع callback های تو در تو به عنوان زنجیره promise مجدداً بیان شوند، که در ادامه مقاله بیشتر به آنها می پردازیم.

قاعد کلی تعریف promise به شکل زیر می باشد :

let promise = new Promise(function(resolve, reject) {
  // executor
});

 

آرگومان ها resolve و reject در callback آبجکت promise که توسط جاوا اسکریپت ارائه شده است فراخوانی می شوند.

در اینجا شما با سه مفهوم رو به رو می شوید که به شرح ذیل می باشد :‌

  • pending: هنگامی که promise ایجاد می شود، در حالت موفقیت یا شکست قرار می گیرد.
  • resolved: هنگامی که promise بازگشت داده می شود و در حالت حل شده قرار می گیرد.
  • fulfilled: هنگامی که promise با موفقیت حل می شود مقدار را برمیگرداند که میتوان با زنجیره زدن then به مقدار آن دسترسی پیدا کرد.
  • rejected:‌ هنگامی که promise بدون موفقیت حل می شود که یک پیغام خطا را برای رد شدن آن برمی گرداند که با زنجیره زدن catch به مقدار آن می توان دسترسی پیدا کرد.

شکل زیر نمایانگر فرایند اجرای promise می باشد:

 

 

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

let example = () => {
   return new Promise(function(resolve, reject) => {
     let value = function1();
     if (job success) {
       resolve(value);
     } else (job unsuccessful) {
       reject(console.log("something's wrong!! :("));
     }
   }).then(function(value)) {
     // success
     return nextFunction(value);
   }).catch(rejectFunction);
  }

 

مفهوم async / awiat

کلمات کلیدی async و await در ES2018 برای کاهش دیگر تکرارات و حل محدودیت "در شکستن زنجیره" در promise ها معرفی شد.

بیایید تفاوت بین Promises و async/await را ببینیم!

 

promise : 

const promise = () => {
  return new Promise(resolve => {
    setTimeout(() => resolve("done!"), 1000);
  })
};

 

async/await :

const promise = async () => {
  console.log(await promiseAsync());
};

 

در نتیجه هنگامی که از async/await استفاده می شود، then/catch به ندرت استفاده می شود. چرا که در درون خود مقادیر به صورت مستفیم به promise مورد نظر برمیگردند و دیگر نیازی به نوشتن زنجیره ای برای آنها نیست .

نتیجه گیری

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

از بهترین نوشته‌های کاربران سکان آکادمی در سکان پلاس


online-support-icon