برای بسیاری از برنامه ها در جاوا اسکریپت ، وقتی برنامه نویس کد را به صورت خط به خط می نویسد در همان زمان اجرا می شود. به این کار اجرای همزمان گفته می شود ، زیرا سطرها یکی پس از دیگری، به ترتیبی که نوشته شده اند اجرا می شوند. با این حال ، هر دستورالعملی که شما به رایانه می دهید نیاز به اجرای فوری ندارد. به عنوان مثال ، اگر درخواست شبکه ارسال می کنید ، فرآیند اجرای کد شما باید منتظر بماند تا داده ها قبل از اجرا بر روی آن برگردند. در این حالت ، اگر در حالی که منتظر تکمیل درخواست شبکه هستید ، کد دیگری را اجرا نکند ، وقت تلف می شود. برای حل این مشکل ، توسعه دهندگان از برنامه نویسی ناهمزمان استفاده می کنند ، که در آن خطوط کد به ترتیب متفاوتی از آنچه نوشته شده اند اجرا می شوند. با برنامه نویسی ناهمزمان ، می توانیم در حالی که منتظر هستیم فعالیتهای طولانی مانند درخواست شبکه به پایان برسد، کدهای دیگری را اجرا کنیم.
کد JavaScript در یک فرآیند کامپیوتری بر روی یک رشته واحد اجرا می شود. کد آن به صورت همزمان در این رشته پردازش می شود و فقط یک دستورالعمل در هر زمان اجرا می شود. بنابراین ، اگر ما می خواستیم یک کار طولانی در این رشته انجام دهیم ، تمام کد باقی مانده تا زمان اتمام آن کار مسدود می شد. با اعمال ویژگی های برنامه نویسی ناهمزمان جاوا اسکریپت ، می توان کارهای طولانی مدت را بر روی یک رشته پس زمینه بارگذاری کرد تا از بروز این مشکل جلوگیری شود. پس از اتمام کار ، کدی که برای پردازش داده های کار نیاز داریم بر روی تک رشته اصلی قرار می گیرد.
در این آموزش ، شما می آموزید که چگونه JavaScript با کمک حلقه رویداد وظایف ناهمزمان را مدیریت می کند، به این شکل که وظیفه جدیدی را هنگام انتظار برای کار دیگر انجام می دهد. سپس برنامه ای را ایجاد می کنید که از برنامه نویسی ناهمزمان استفاده می کند تا لیستی از فیلم ها را از یک Studio Ghibli API درخواست کرده و داده ها را در یک فایل CSV ذخیره کنید. کد ناهمزمان به سه روش نوشته خواهد شد: callback ، promise ها ، و با کلمات کلیدی async/await.
توجه: طبق این نوشتار ، برنامه نویسی ناهمزمان دیگر فقط با استفاده از تماسهای برگشتی انجام نمی شود ، اما یادگیری این روش منسوخ می تواند زمینه ای را فراهم کند که نشان دهد چرا جامعه جاوا اسکریپت اکنون از promise ها استفاده میکنند. کلمات کلیدی async / await به ما این امکان را می دهد که از promise ها به روشی کوتاه تر استفاده کنیم ، و به این ترتیب روشی استاندارد برای انجام برنامه نویسی ناهمزمان در جاوا اسکریپت در زمان نوشتن این مقاله میباشد.

پیش نیازها
Node.js بر روی دستگاه توسعه شما نصب شده باشد. در این آموزش از نسخه 10.17.0 استفاده شده است. برای نصب این در macOS یا Ubuntu 18.04 ، مراحل نحوه نصب Node.js و ایجاد محیط توسعه محلی در macOS یا نصب با استفاده از یک بخش PPA را در راهنمای نحوه نصب Node.js در اوبونتو 18.04 دنبال کنید.
همچنین باید با نصب بسته ها در پروژه خود آشنا باشید. با خواندن راهنمای ما در مورد چگونگی استفاده از ماژول های Node.js با npm و pack.json سریعتر پیش روید.
مهم است که قبل از یادگیری چگونگی استفاده از توابع به صورت ناهمزمان ، برای ایجاد و اجرای توابع در جاوا اسکریپت مشکلی نداشته باشید. اگر به معرفی یا اطلاعات تکمیلی نیاز دارید می توانید راهنمای ما در مورد چگونگی تعریف توابع در JavaScript را بخوانید.
حلقه رویداد
بیایید با مطالعه عملکرد داخلی اجرای عملکرد JavaScript شروع کنیم. درک نحوه این رفتار به شما امکان می دهد تا کدهای ناهمزمان را سنجیده تر بنویسید ، و در آینده به شما در زمینه عیب یابی کد کمک می کند.
از آنجا که مترجم جاوا اسکریپت کد را اجرا می کند ، هر عملکردی که خوانده می شود به call stack در جاوا اضافه می شود. call stack یک ساختار داده لیست مانند است که در آن موارد فقط به بالا می توانند اضافه شوند و از بالا حذف شوند. stack ها از اصل “از آخر وارد شو ، از اول خارج شو” یا LIFO پیروی می کنند. اگر دو مورد را روی stack اضافه کنید ، آخرین مورد اول حذف می شود.
بگذارید با یک مثال با استفاده از call stack ، توضیح دهیم. اگر جاوا اسکریپت با یک تابع functionA () فراخوانی شود ، به call stack اضافه می شود. اگر آن تابع functionA () یکی دیگر از عملکردهای functionB () را فراخوانی کند ، سپس functionB () به قسمت بالای call stack اضافه می شود. همانطور که جاوا اسکریپت اجرای یک عملکرد را کامل می کند ، از call stack حذف می شود. بنابراین جاوا اسکریپت ابتدا functionB () را اجرا می کند ، پس از اتمام آن را از stack جدا میکند و سپس اجرای functionA () را تمام میکند و آن را از call stack حذف میکند. به همین دلیل است که عملکردهای داخلی همیشه قبل از کارکردهای بیرونی آنها اجرا می شوند.
هنگامی که جاوا اسکریپت با یک عمل ناهمزمان مواجه می شود ، مانند نوشتن یک فایل ، آن را به یک جدول در حافظه خود اضافه می کند. این جدول عملکرد را ذخیره میند ، شرط تکمیل اجرای آن و فراخوانی تابغ هنگام اتمام است. با اتمام عمل ، JavaScript عملکرد مرتبط را در صف پیام قرار می دهد. یک صف دیگر ساختار داده لیست مانند است که در آن موارد فقط می توانند به پایین اضافه شوند اما از بالا حذف شوند. در صف پیام ، اگر دو یا چند عملیات ناهمزمان برای اجرای وظایف خود آماده باشد ، عملیات ناهمزمان که ابتدا به اتمام رسیده است ، ابتدا عملکرد خود را برای اجرا مشخص می کند.
توابع در صف پیام منتظرند که به call stack اضافه شوند. این حلقه رویداد یک روند دائمی است که بررسی می کند ایا call stack خالی است یا خیر. اگر اینگونه باشد ، اولین مورد در صف پیام به call stack منتقل می شود. جاوا اسکریپت عملکردهای موجود در صف پیام را بر حسب عملکرد که در کد آن تفسیر می کند، در اولویت بندی قرار می دهد. اثر ترکیبی call stack ، صف پیام و حلقه رویداد اجازه می دهد تا هنگام مدیریت فعالیت های ناهمزمان ، کد JavaScript پردازش شود.
اکنون که درک درستی از حلقه رویداد دارید ، می دانید کد ناهمزمانی که می نویسید چگونه اجرا می شود. با استفاده از این دانش ، اکنون می توانید با سه رویکرد متفاوت ، کد ناهمزمان ایجاد کنید: callback ، promise ها ، و async / await.
برنامه نویسی ناهمزمان با callback
یک عملکرد برگشتی عملکردی است که به عنوان آرگومان به عملکرد دیگر منتقل می شود ، و بعد از اتمام کار دیگر اجرا می شود. ما از callback برای اطمینان از اجرای کد درست بعد از اتمام عملکرد ناهمزمان استفاده می کنیم.
برای مدت ها ، callback رایج ترین مکانیسم برای نوشتن کد ناهمزمان بودند ، اما اکنون اکثرا منسوخ شده اند زیرا می توانند خواندن کد را گیج کننده جلوه دهند. در این مرحله ، نمونه ای از کد ناهمزمان را با استفاده از callback می نویسید تا بتوانید از آن به عنوان مبانی اولیه استفاده کنید تا بهره وری دیگر استراتژی های دیگر را ببینید.
روشهای زیادی برای استفاده از توابع برگشتی در عملکردهای دیگر وجود دارد. به طور کلی ، آنها از این ساختار استفاده می کنند:
function asynchronousFunction([ Function Arguments ], [ Callback Function ]) {
[ Action ]
}

اگرچه برای JavaScript یا Node.js به لحاظ دستوری الزامی نیست که عملکرد callback  را به عنوان آخرین آرگومان عملکرد بیرونی را داشته باشد ، این یک روش معمول است که شناسایی callback  ها را آسان تر می کند. همچنین معمول است که توسعه دهندگان JavaScript از یک عملکرد ناشناس به عنوان callback  استفاده کنند. توابع ناشناس مواردی هستند که بدون نام ایجاد می شوند. معمولاً وقتی یک عملکرد در انتهای لیست آرگومان ها تعریف می شود ، بیشتر قابل خواندن است.
برای توضیح callback ها ، بیایید یک ماژول Node.js ایجاد کنیم که لیستی از فیلم های Studio Ghibli  را در یک فایل می نویسد. ابتدا پوشه ای ایجاد کنید که فایل جاوا اسکریپت و خروجی آن را ذخیره کند:
$ mkdir ghibliMovies
سپس آن پوشه را وارد کنید:
$ cd ghibliMovies
با ایجاد درخواست HTTP به Studio Ghibli API شروع خواهیم کرد که عملکرد callback ما نتایج آن را ثبت می کند. برای این کار ، کتابخانه ای را نصب می کنیم که به ما امکان می دهد به داده های پاسخ HTTP در یک callback دسترسی پیدا کنیم.
در ترمینال خود، npm را آغاز کنید تا بعداً بتوانیم برای بسته های خود مرجع داشته باشیم:
$ npm init -y
سپس ، كتابخانه request را نصب كنید:
$ npm i request –save
اکنون یک فایل جدید با نام callbackMovies.js در یک ویرایشگر متنی مانند nano باز کنید:
$ nano callbackMovies.js
در ویرایشگر متن خود کد زیر را وارد کنید. بیایید با ارسال یک درخواست HTTP با ماژول request  شروع کنیم:
callbackMovies.js
const request = require(‘request’);

request(‘https://ghibliapi.herokuapp.com/films’);

در خط اول ماژول درخواستی را که از طریق npm نصب شده است بارگذاری می کنیم. ماژول تابعی را برمی گرداند که می تواند درخواست HTTP ایجاد کند . سپس آن عملکرد را در request  به صورت ثابت ذخیره می کنیم.
سپس با استفاده از عملکرد request() درخواست HTTP را انجام می دهیم. اکنون بیایید با افزودن تغییرات هایلایت شده ، داده های درخواست HTTP را برای چاپ به کنسول ارسال کنیم:
callbackMovies.js
const request = require(‘request’);

request(‘https://ghibliapi.herokuapp.com/films’, (error, response, body) => {
if (error) {
console.error(`Could not send request to API: ${error.message}`);
return;
}

if (response.statusCode != 200) {
console.error(`Expected status code 200 but received ${response.statusCode}.`);
return;
}

console.log(‘Processing our list of movies’);
movies = JSON.parse(body);
movies.forEach(movie => {
console.log(`${movie[‘title’]}, ${movie[‘release_date’]}`);
});
});

وقتی از تابع request() استفاده می کنیم ، به آن دو پارامتر می دهیم:
آدرس URL وب سایتی که می خواهیم درخواست بدهیم
عملکرد callback که پس از تکمیل درخواست ، خطاها یا پاسخ های موفقیت آمیز را مدیریت می کند
عملکرد callback  ما سه آرگومان دارد: error ، response و body. هنگامی که درخواست HTTP کامل شد ، آرگومان ها بسته به نتیجه به طور خودکار مقادیر میگیرند. اگر درخواست نتواند ارسال شود ، error حاوی یک موضوع است ، اما response و body ، null خواهند بود. اگر درخواست را با موفقیت انجام داد ، پاسخ HTTP در response ذخیره می شود. اگر پاسخ HTTP ما داده ها را برگرداند (در این مثال JSON را دریافت می کنیم) سپس داده ها به صورت body تنظیم می شوند.
عملکرد callback  ما ابتدا بررسی می کند که آیا خطایی دریافت کرده ایم یا خیر. بهترین کار این است که ابتدا خطاها را در یک callback  بررسی کنید تا اجرای callback  با داده های از دست رفته ادامه پیدا نکند. در این حالت خطا و اجرای عملکرد را ثبت می کنیم. سپس کد وضعیت پاسخ را بررسی می کنیم. سرور مجازی ما ممکن است همیشه در دسترس نباشد و API ها می توانند تغییر کنند و باعث نادرست شدن درخواست های معقول شوند. با بررسی اینکه کد وضعیت 200 است ، به این معنی که درخواست “OK” است ، می توانیم اطمینان داشته باشیم که پاسخ ما همان چیزی است که انتظار داریم.
سرانجام ، body پاسخ را به یک Array تجزیه کرده و از طریق هر فیلم حلقه می کنیم تا نام و سال انتشار آن ثبت شود.
پس از ذخیره و خروج از فایل ، این اسکریپت را با دستور زیر اجرا کنید:
$ node callbackMovies.js
خروجی زیر را دریافت خواهید کرد:
Output
Castle in the Sky, 1986
Grave of the Fireflies, 1988
My Neighbor Totoro, 1988
Kiki’s Delivery Service, 1989
Only Yesterday, 1991
Porco Rosso, 1992
Pom Poko, 1994
Whisper of the Heart, 1995
Princess Mononoke, 1997
My Neighbors the Yamadas, 1999
Spirited Away, 2001
The Cat Returns, 2002
Howl’s Moving Castle, 2004
Tales from Earthsea, 2006
Ponyo, 2008
Arrietty, 2010
From Up on Poppy Hill, 2011
The Wind Rises, 2013
The Tale of the Princess Kaguya, 2013
When Marnie Was There, 2014

ما لیستی از فیلمهای Studio Ghibli را با سالی که اکران شدند دریافت کردیم. اکنون بگذارید این برنامه را با نوشتن لیست فیلم هایی که در حال حاضر در فایل هست تکمیل کنیم.
فایل callbackMovies.js را در ویرایشگر متن خود به روز کنید تا کد هایلایت شده زیر را شامل شود ، که یک فایل CSV را با داده های فیلم ما ایجاد می کند:
callbackMovies.js
const request = require(‘request’);
const fs = require(‘fs’);

request(‘https://ghibliapi.herokuapp.com/films’, (error, response, body) => {
if (error) {
console.error(`Could not send request to API: ${error.message}`);
return;
}

if (response.statusCode != 200) {
console.error(`Expected status code 200 but received ${response.statusCode}.`);
return;
}

console.log(‘Processing our list of movies’);
movies = JSON.parse(body);
let movieList = ”;
movies.forEach(movie => {
movieList += `${movie[‘title’]}, ${movie[‘release_date’]}\n`;
});

fs.writeFile(‘callbackMovies.csv’, movieList, (error) => {
if (error) {
console.error(`Could not save the Ghibli movies to a file: ${error}`);
return;
}

console.log(‘Saved our list of movies to callbackMovies.csv’);;
});
});

با دقت به تغییرات هایلایت شده ، می بینیم که ماژول fs را وارد کردیم. این ماژول در تمام نصب های Node.js استاندارد است و شامل روش writeFile () است که می تواند به صورت غیر همزمان در یک فایل بنویسد.
به جای اینکه داده ها را به کنسول وارد کنیم ، اکنون آن را به یک متغیر رشته ای movieList اضافه می کنیم. سپس از writeFile() براي ذخيره محتواي movieList در یک فایل جدید به نام callbackMovies.csv استفاده مي كنيم. سرانجام ، برای تابع writeFile () یک callback ارائه می دهیم که یک آرگومان دارد: erorr. این به ما امکان می دهد مواردی را کنترل کنیم که قادر به نوشتن روی یک فایل نیستیم ، به عنوان مثال وقتی کاربری که فرآیند node را در آن اجرا می کنیم ، آن مجوزها را ندارد.
فایل را ذخیره کرده و این برنامه Node.js را بار دیگر با دستور زیر اجرا کنید:
$ node callbackMovies.js
در پوشه ghibliMovies ، callbackMovies.csv را مشاهده خواهید کرد که دارای محتوای زیر است:
callbackMovies.csv
Castle in the Sky, 1986
Grave of the Fireflies, 1988
My Neighbor Totoro, 1988
Kiki’s Delivery Service, 1989
Only Yesterday, 1991
Porco Rosso, 1992
Pom Poko, 1994
Whisper of the Heart, 1995
Princess Mononoke, 1997
My Neighbors the Yamadas, 1999
Spirited Away, 2001
The Cat Returns, 2002
Howl’s Moving Castle, 2004
Tales from Earthsea, 2006
Ponyo, 2008
Arrietty, 2010
From Up on Poppy Hill, 2011
The Wind Rises, 2013
The Tale of the Princess Kaguya, 2013
When Marnie Was There, 2014

توجه به این نکته مهم است که ما در پاسخ به درخواست HTTP در فایل CSV خود می نویسیم. هنگامی که کد در عملکرد callback قرار دارد ، تنها پس از تکمیل درخواست HTTP برای فایل نوشته خواهد شد. اگر می خواستیم بعد از نوشتن فایل CSV خود با یک بانک اطلاعاتی ارتباط برقرار کنیم ، عملکرد غیر ناهمزمان دیگری را ایجاد می کردیم که در پاسخ به writeFile () فراخوانی می شد. هرچه کد غیر ناهمزمان بیشتری داشته باشیم ، عملکردهای callback بیشتری باید سکنی گزیده شوند.
بیایید تصور کنیم که می خواهیم پنج عملیات ناهمزمان را انجام دهیم ، هر کدام فقط در صورت کامل شدن دیگری قادر به اجرا هستند. اگر ما این را کدگذاری می کردیم ، چیزی شبیه به این داشتیم:
doSomething1(() => {
doSomething2(() => {
doSomething3(() => {
doSomething4(() => {
doSomething5(() => {
// final action
});
});
});
});
});

هنگامی که callback های تو در تو خطوط زیادی برای اجرای کد دارند ، بسیار پیچیده تر و غیرقابل خواندن می شوند. هرچه اندازه و پیچیدگی پروژه جاوا اسکریپت بزرگ تر شود ، تا زمانی که نهایتا قابل کنترل نباشد ، این اثر برجسته تر می شود. به همین دلیل ، توسعه دهندگان دیگر از callback برای انجام عملیات غیر همزمان استفاده نمی کنند. برای بهبود دستورات کد ناهمزمان ، می توانیم به جای آن از promise ها استفاده کنیم.
استفاده از promise ها برای برنامه نویسی ناهمزمان مختصر
یک promise یک موضوع JavaScript است که در آینده مقداری را به شما باز می گرداند. توابع ناهمزمان میتوانند به جای مقادیر در هم تنیده، موضوعات promise را برگردانند. اگر در آینده مقداری را دریافت کنیم ، می گوییم این promise تحقق یافته است. اگر در آینده با ارور مواجه شویم ، می گوییم این promise رد شده است. در غیر این صورت ، این promise هنوز در حالت معلق در حال کار است.
promise ها به طور کلی شکل زیر را دارند:
promiseFunction()
.then([ Callback Function for Fulfilled Promise ])
.catch([ Callback Function for Rejected Promise ])

همانطور که در این الگو نشان داده شده است ، promise ها همچنین از توابع callback استفاده می کنند. ما یک تابع callback برای متد then () داریم که وقتی یک promise برآورده می شود اجرا می شود. ما همچنین یک تابع callback برای روش catch() داریم تا خطایی را که هنگام اجرای promise اجرا می شود ، برطرف کنیم.
بیایید با بازنویسی برنامه Studio Ghibli برای استفاده از promise ها ، اولین تجربه را با promise ها بدست آوریم.
Axios یک سرویس دهنده HTTP مبتنی بر promise برای JavaScript است ، بنابراین بیایید ادامه دهیم و آن را نصب کنیم:
$ npm i axios –save
اکنون ، با ویرایشگر متن مورد نظر خود ، یک فایل جدید premMovies.js ایجاد کنید:
$ nano promiseMovies.js
برنامه ما درخواست HTTP را با axios انجام می دهد و سپس از نسخه ویژه promise داده شده مبتنی بر fs برای ذخیره در فایل جدید CSV استفاده می کند.
این کد را در premMovies.js تایپ کنید تا بتوانیم Axios را بارگذاری کنیم و یک درخواست HTTP را به فیلم API ارسال کنیم:
promiseMovies.js
const axios = require(‘axios’);

axios.get(‘https://ghibliapi.herokuapp.com/films’);

در خط اول ماژول axios را بارگذاری می کنیم ، عملکرد برگشتی را در فایل ثابت به نام axios ذخیره می کنیم. سپس از روش axios.get () برای ارسال درخواست HTTP به API استفاده می کنیم.
روش axios.get () ، promise را بر می گرداند. بگذارید این promise را زنجیره ای کنیم تا بتوانیم لیست فیلمهای Ghibli را روی کنسول چاپ کنیم:
promiseMovies.js
const axios = require(‘axios’);
const fs = require(‘fs’).promises;

axios.get(‘https://ghibliapi.herokuapp.com/films’)
.then((response) => {
console.log(‘Successfully retrieved our list of movies’);
response.data.forEach(movie => {
console.log(`${movie[‘title’]}, ${movie[‘release_date’]}`);
});
})

بگذارید آنچه را که اتفاق می افتد تجزیه کنیم. پس از درخواست HTTP GET با axios.get () ، ما از تابع then() استفاده می کنیم ، که فقط در صورت تحقق promise اجرا می شود. در این حالت ، فیلم ها را مانند مثال callbacks روی صفحه نمایش چاپ می کنیم.
برای بهبود این برنامه ، کد هایلایت شده را برای نوشتن داده های HTTP به یک فایل اضافه کنید:
promiseMovies.js
const axios = require(‘axios’);
const fs = require(‘fs’).promises;

axios.get(‘https://ghibliapi.herokuapp.com/films’)
.then((response) => {
console.log(‘Successfully retrieved our list of movies’);
let movieList = ”;
response.data.forEach(movie => {
movieList += `${movie[‘title’]}, ${movie[‘release_date’]}\n`;
});

return fs.writeFile(‘promiseMovies.csv’, movieList);
})
.then(() => {
console.log(‘Saved our list of movies to promiseMovies.csv’);
})

ما علاوه بر این ماژول fs را بار دیگر وارد می کنیم. توجه داشته باشید که پس از وارد کردن fs چگونه promise داریم. Node.js شامل نسخه مبتنی بر promise از کتابخانه fs مبتنی بر callback است، بنابراین سازگاری رو به عقب در پروژه های بعدی از بین نمیرود.
اولین عملکرد then() که پردازش درخواست HTTP را انجام می دهد ، اکنون به جای چاپ برای کنسول ، fs.writeFile () را فراخوانی می کند. از آنجا که ما نسخه fs مبتنی بر promise را وارد کردیم ، عملکرد writeFile() ما promise دیگری را برمی گرداند. به این ترتیب ، ما عملکرد then() دیگری را برای زمان تحقق promise writeFile()ایجاد می کنیم.
یک promise می تواند یک promise جدید را برگرداند و به ما امکان می دهد promise های خود را یکی پس از دیگری اجرا کنیم. این امر مسیری را برای ما فراهم می کند که چندین عملیات ناهمزمان را انجام دهیم. به این عمل، زنجیره promise گفته می شود و شبیه به callbackهای تو در تو است. then() دوم فقط پس از آنكه فایل را با موفقیت نوشتیم فراخوانی می شود.
توجه: در این مثال ، ما کد وضعیت HTTP را مانند آنچه در مثال callback انجام دادیم ، بررسی نکردیم. به طور پیش فرض ، axios در صورت دریافت کد وضعیت نشانگر خطا ، به promise خود عمل نمی کند. به همین ترتیب ، دیگر نیازی به اعتبار سنجی آن نداریم.

برای تکمیل این برنامه ، promise را با عملکرد catch() مانند چیزی که در شکل زیر هایلاین شده است زنجیر کنید:
promiseMovies.js
const axios = require(‘axios’);
const fs = require(‘fs’).promises;

axios.get(‘https://ghibliapi.herokuapp.com/films’)
.then((response) => {
console.log(‘Successfully retrieved our list of movies’);
let movieList = ”;
response.data.forEach(movie => {
movieList += `${movie[‘title’]}, ${movie[‘release_date’]}\n`;
});

return fs.writeFile(‘promiseMovies.csv’, movieList);
})
.then(() => {
console.log(‘Saved our list of movies to promiseMovies.csv’);
})
.catch((error) => {
console.error(`Could not save the Ghibli movies to a file: ${error}`);
});

اگر در زنجیره ی promise ها هیچ یک از promiseها عملی نشد، JavaScript به طور خودکار به تابع catch() می رود. به همین دلیل ما فقط یک شرط catch() داریم حتی اگر دو عملیات ناهمزمان داشته باشیم.
با اجرای دستور زیر بیایید تأیید کنیم که برنامه ما همان خروجی را تولید می کند:
$ node promiseMovies.js
در پوشه ghibliMovies ، فایل sozdaMovies.csv را مشاهده خواهید کرد که شامل موارد زیر است:
promiseMovies.csv
Castle in the Sky, 1986
Grave of the Fireflies, 1988
My Neighbor Totoro, 1988
Kiki’s Delivery Service, 1989
Only Yesterday, 1991
Porco Rosso, 1992
Pom Poko, 1994
Whisper of the Heart, 1995
Princess Mononoke, 1997
My Neighbors the Yamadas, 1999
Spirited Away, 2001
The Cat Returns, 2002
Howl’s Moving Castle, 2004
Tales from Earthsea, 2006
Ponyo, 2008
Arrietty, 2010
From Up on Poppy Hill, 2011
The Wind Rises, 2013
The Tale of the Princess Kaguya, 2013
When Marnie Was There, 2014

با promise ها ، می توانیم کد مختصرتری نسبت به callback صرف بنویسیم. زنجیره promise برای callbackها گزینه ای شفاف تر نسبت به لانه گزینی callbackها است. با این حال ، هنگامی که ما تماس های غیر همزمان برقرار میکنیم ، زنجیره promise ما طولانی تر و حفظ آن سخت تر می شود.
صریح بودن callbackها و promise ها ناشی از نیاز به ایجاد توابعی است که نتیجه کار غیر ناهمزمان را داشته باشیم. تجربه بهتر، انتظار برای نتیجه ناهمزمان و قرار دادن آن در متغیری خارج از تابع است. به این ترتیب ، می توانیم از نتایج در متغیرها استفاده کنیم بدون اینکه تابعی داشته باشیم. ما می توانیم با کلمات کلیدی async و await به این هدف برسیم.
نوشتن JavaScript با async / await
کلمات کلیدی async / await در هنگام کار با promise ها دستور دیگری را ارائه می دهند. به جای اینکه نتیجه یک promise موجود در روش then() را داشته باشیم ، نتیجه به عنوان یک مقدار مانند هر تابع دیگر بازگردانده می شود. ما یک تابع را با کلمه کلیدی async تعریف می کنیم تا به JavaScript بگوییم که این یک عملکرد ناهمزمان است که promise را برمی گرداند. از کلمه کلیدی await استفاده می کنیم تا به JavaScript بگوییم که به جای بازگرداندن خود promise هنگام اجرا ، نتایج promise را برگرداند.
به طور کلی ، استفاده از async/await این چنین است:
async function() {
await [Asynchronous Action]
}

بیایید ببینیم که چگونه استفاده از async / await می تواند برنامه Studio Ghibli ما را بهبود ببخشد. از ویرایشگر متن خود برای ایجاد و باز کردن فایل جدید asyncAwaitMovies.js استفاده کنید:
$ nano asyncAwaitMovies.js
در فایل JavaScript که به تازگی باز شده است ، بیایید با وارد کردن همان ماژول هایی که در مثال promise خود استفاده کرده ایم، شروع کنیم:
asyncAwaitMovies.js
const axios = require(‘axios’);
const fs = require(‘fs’).promises;

ورودی ها همانند premMovies.js است زیرا async / await از promise ها استفاده می کند.
اکنون ما از کلمه کلیدی async برای ایجاد تابعی با کد ناهمزمان استفاده می کنیم:
asyncAwaitMovies.js
const axios = require(‘axios’);
const fs = require(‘fs’).promises;

async function saveMovies() {}

ما یک تابع جدید به نام saveMovies () ایجاد می کنیم اما async را در ابتدای تعریف آن قرار می دهیم. این مسئله از این جهت مهم است که ما فقط می توانیم از کلمه کلیدی await در یک عملکرد غیرهمزمان استفاده کنیم.
از کلمه کلیدی await استفاده کنید تا یک درخواست HTTP ایجاد کنید که لیست فیلم ها را از Ghibli API دریافت می کند:
asyncAwaitMovies.js
const axios = require(‘axios’);
const fs = require(‘fs’).promises;

async function saveMovies() {
let response = await axios.get(‘https://ghibliapi.herokuapp.com/films’);
let movieList = ”;
response.data.forEach(movie => {
movieList += `${movie[‘title’]}, ${movie[‘release_date’]}\n`;
});
}

در عملکرد saveMovies () ما مانند گذشته درخواست HTTP را با axios.get () انجام می دهیم. این بار ، ما آن را با یک تابع then() زنجیر نمی کنیم. در عوض ، قبل از اینکه فراخوانی شود ، await را اضافه می کنیم. هنگامی که جاوا اسکریپت await را می بیند ، تنها پس از اتمام axios.get ()کد باقی مانده تابع را اجرا می کند و متغیر response را تنظیم می کند. کد دیگر داده های فیلم را ذخیره می کند بنابراین می توانیم در یک فایل بنویسیم.
بگذارید داده های فیلم را در یک فایل بنویسیم:
asyncAwaitMovies.js
const axios = require(‘axios’);
const fs = require(‘fs’).promises;

async function saveMovies() {
let response = await axios.get(‘https://ghibliapi.herokuapp.com/films’);
let movieList = ”;
response.data.forEach(movie => {
movieList += `${movie[‘title’]}, ${movie[‘release_date’]}\n`;
});
await fs.writeFile(‘asyncAwaitMovies.csv’, movieList);
}

همچنین وقتی با fs.writeFile ()در فایل مینوسیم از کلمه کلیدی await استفاده می کنیم.
برای تکمیل این عملکرد ، باید خطاهایی را پیدا کنیم که promise های ما می توانند ایجاد کنند. بیایید این کار را با کپسوله کردن کد خود در یک محفظه try/catch انجام دهیم:
asyncAwaitMovies.js
const axios = require(‘axios’);
const fs = require(‘fs’).promises;

async function saveMovies() {
try {
let response = await axios.get(‘https://ghibliapi.herokuapp.com/films’);
let movieList = ”;
response.data.forEach(movie => {
movieList += `${movie[‘title’]}, ${movie[‘release_date’]}\n`;
});
await fs.writeFile(‘asyncAwaitMovies.csv’, movieList);
} catch (error) {
console.error(`Could not save the Ghibli movies to a file: ${error}`);
}
}

از آنجا که promise ها می توانند با شکست مواجه شوند ، ما کد ناهمزمان خود را با یک عبارت try/catch رمزگذاری می کنیم. با این کار در صورت عدم موفقیت درخواست HTTP یا عملیات نوشتن فایل ، هر گونه خطایی یافت میشود.
در آخر ، بیایید تابع ناهمزمان saveMovies() را فراخوانی کنیم ، تا وقتی برنامه را با node اجرا می کنیم ، عملی شود
asyncAwaitMovies.js
const axios = require(‘axios’);
const fs = require(‘fs’).promises;

async function saveMovies() {
try {
let response = await axios.get(‘https://ghibliapi.herokuapp.com/films’);
let movieList = ”;
response.data.forEach(movie => {
movieList += `${movie[‘title’]}, ${movie[‘release_date’]}\n`;
});
await fs.writeFile(‘asyncAwaitMovies.csv’, movieList);
} catch (error) {
console.error(`Could not save the Ghibli movies to a file: ${error}`);
}
}

saveMovies();

در یک نگاه ، مانند یک بلوک کد همزمان JavaScript به نظر می رسد. عملکردهای کمتری در اطراف آن منتقل می شود که کمی ساده تر به نظر می رسد. این ترفندهای کوچک باعث می شود کد ناهمزمان با async/await راحت تر حفظ شود.
با وارد کردن این قسمت در ترمینال خود ، این تکرار برنامه را امتحان کنید:
$ node asyncAwaitMovies.js
در پوشه ghibliMovies ، فایل جدید asyncAwaitMovies.csv با محتوای زیر ایجاد می شود:
asyncAwaitMovies.csv
Castle in the Sky, 1986
Grave of the Fireflies, 1988
My Neighbor Totoro, 1988
Kiki’s Delivery Service, 1989
Only Yesterday, 1991
Porco Rosso, 1992
Pom Poko, 1994
Whisper of the Heart, 1995
Princess Mononoke, 1997
My Neighbors the Yamadas, 1999
Spirited Away, 2001
The Cat Returns, 2002
Howl’s Moving Castle, 2004
Tales from Earthsea, 2006
Ponyo, 2008
Arrietty, 2010
From Up on Poppy Hill, 2011
The Wind Rises, 2013
The Tale of the Princess Kaguya, 2013
When Marnie Was There, 2014

اکنون برای مدیریت کد ناهمزمان از ویژگیهای async/await در JavaScript استفاده کرده ایم.
نتیجه
در این آموزش ، شما یاد گرفتید که چگونه JavaScript توابع اجرایی و مدیریت عملیات ناهمزمان را با حلقه رویداد کنترل می کند. سپس برنامه هایی را نوشتید که پس از درخواست HTTP برای داده های فیلم با استفاده از تکنیک های مختلف برنامه نویسی ناهمگام ، فایل CSV ایجاد کرده اند. ابتدا ، از رویکرد منسوخ بر اساس callback استفاده کردید. سپس از promise ها ، و در نهایت async/await استفاده کردید که ترکیب promise را خلاصه تر میکند.
با درک کنونی خود از کد ناهمزمان با Node.js ، می توانید برنامه هایی را تهیه کنید که از برنامه نویسی ناهمزمان بهره مند میشوند ، مانند برنامه هایی که به تماس های API وابسته اند. به این لیست از API های عمومی نگاهی بیندازید. برای استفاده از آنها ، شما باید درخواستهای HTTP ناهمزمان مانند آنچه در این آموزش انجام دادیم را ایجاد کنید. برای مطالعه بیشتر ، سعی کنید برنامه ای بسازید که از این API ها استفاده کند تا تکنیک هایی را که در اینجا آموخته اید تمرین کنید.

 

نحوه میزبانی وب سایت با استفاده از Cloudflare و Nginx در اوبونتو 20.04

چگونه می توان با Stunnel و redis-cli به یک Redis نمونه مدیریت شده از طریق TLS متصل شد

چگونگی توسعه وب سایت Drupal 9 در دستگاه محلی خود با استفاده از Docker و DDEV

نحوه راه اندازی بستگی به سیستم عامل برنامه Eclipse Theia Cloud IDE در اوبونتو 18.04 [Quickstart]

نحوه استفاده از Cron برای خودکارسازی کارها در CentOS 8

نحوه نوشتن کد ناهمگام (غیر همزمان) در Node.js

نحوه تنظیم Mattermost در اوبونتو 20.04

نحوه ساخت یک ربات Discord با Node.js

نحوه پیکربندی Jenkins با SSL با استفاده از پروکسی معکوس Nginx در اوبونتو 20.04

نحوه نصب چهارچوب وب Django در اوبونتو 20.04

 

کلمات کلیدی خرید سرور

خرید vps – خرید سرور مجازی – خرید سرور – سرور هلند – فروش vps – سرور مجازی آمریکا – خریدvps – سرور مجازی هلند – فروش سرور مجازی – سرور آمریکا – vps – سرور مجازی انگلیس – سرور مجازی آلمان – سرور مجازی کانادا – خرید vps آمریکا – خرید وی پی اس – سرور – خرید سرور مجازی هلند – vps خرید – سرور مجازی فرانسه – سرور مجازی هلند – خرید vps آمریکاخرید سرور مجازی ارزان هلندvpsخرید vps هلندخرید سرور مجازی آمریکاخرید vps فرانسهتست vpsسرور مجازی تستسرور مجازی ویندوزارزانترین vpsخرید وی پی اسvps ارزان –