به عنوان یک توسعه دهنده، طبیعتاً می خواهم نرم افزارم قابل اعتماد و پاسخگو باشد. در روزهای اولیه کار من، بازخوردها در مورد برنامه های من متفاوت بود. برخی از برنامهها امتیاز بالایی کسب کردند، اما بررسیها در مورد سایر برنامهها متناقض بود، زیرا بهطور متناوب در اواسط جلسه پاسخ نمیدهند – و همه ما میدانیم که کاربران نهایی برای پاسخگویی ضعیف برنامه چقدر صبر کمی دارند.
مشکل اساسی این بود که برنامه ها با استفاده از جاوا اسکریپت کاملاً همزمان کدگذاری شده بودند. از آنجایی که جاوا اسکریپت توابع ناهمزمان (به ظاهر) را ارائه می دهد، به راحتی می توان از این واقعیت غافل شد که زمان اجرا جاوا اسکریپت به طور پیش فرض همزمان است و این یک دام بالقوه برای توسعه دهندگان است. کنجکاوی من را به بررسی این معمای برنامه ای سوق داد.
مشکل: مسدود کردن همزمان جاوا اسکریپت
کاوش خود را با مشاهده روشی که تماسهای منظم و همزمان کار میکنند، و تمرکز تلاشهایم بر روی پشتههای تماس آغاز کردم.برنامه نویسی last in, first out (LIFO). سازه های.
همه پشته های فراخوانی بدون در نظر گرفتن زبان یکسان عمل می کنند: ما push
(افزودن) تابع را به پشته و سپس فراخوانی می کند pop
(در صورت نیاز) آنها را بردارید.
بیایید یک مثال کوتاه را در نظر بگیریم:
function multiply(a, b) {
return a * b;
}
function square(n) {
return multiply(n, n);
}
function printSquare(n) {
const squaredNum = square(n);
console.log(squaredNum);
}
printSquare(4);
در مثال ما، خارجی ترین تابع، printSquare
، تماس می گیرد square
تابع، که به نوبه خود فراخوانی می کند multiply
. توابع به ترتیبی که با آنها مواجه می شوند به پشته تماس ما اضافه می شوند. با تکمیل هر روش، از انتهای پشته تماس حذف می شود (یعنی، multiply
ابتدا حذف خواهد شد).
از آنجایی که پشته تماس همزمان است، زمانی که تکمیل یک یا چند مورد از این توابع به زمان قابل توجهی نیاز دارد، کارهای باقی مانده مسدود می شوند. برنامه ما پاسخگو نمی شود – حداقل به طور موقت – و تنها زمانی از سر گرفته می شود که عملکرد مسدود شده تکمیل شود.
فراخوانی های تابع متداول که منجر به تاخیرهای برنامه می شود عبارتند از:
- آ
while
حلقه با تعداد تکرار بالا (به عنوان مثال، از یک تا یک تریلیون). - درخواست شبکه به یک وب سرور خارجی.
- رویدادی که منتظر تایمر است تا کامل شود.
- پردازش تصویر.
برای کاربران نهایی در یک مرورگر وب، انسداد تماسهای همزمان منجر به ناتوانی در تعامل با عناصر صفحه میشود. و برای توسعه دهندگان، این تماس های گیر کرده کنسول توسعه را غیرقابل دسترسی می کند و توانایی بررسی اطلاعات دقیق اشکال زدایی را از بین می برد.
راه حل: عملکرد جاوا اسکریپت ناهمزمان
کدگذاری ناهمزمان یک تکنیک برنامه نویسی است که در آن، پس از فراخوانی یک تابع، باقیمانده کد ما می تواند بدون نیاز به منتظر ماندن برای بازگشت تابع اولیه اجرا شود. هنگامی که یک کار ناهمزمان کامل می شود، زمان اجرا جاوا اسکریپت نتیجه را به تابعی که ما انتخاب می کنیم ارسال می کند. این روش موانع را برای کاربران نهایی و توسعه دهندگان ما از بین می برد.
جاوا اسکریپت عملکرد ناهمزمان را از طریق چند جزء کلیدی معماری پیاده سازی می کند:
هر چیزی که باید به صورت ناهمزمان اجرا شود (به عنوان مثال، یک تایمر یا تماس API خارجی) به API مرورگر موتور زمان اجرا (web API) ارسال می شود. API مرورگر در هر عملیاتی که در مسیر خود قرار می گیرد، یک رشته اجرایی واحد ایجاد می کند.
هر فراخوانی تابع ناهمزمان جاوا اسکریپت که به API مرورگر ارسال میشود، یک وعده متناظر دارد که به کد کنترل کننده اجازه میدهد هنگام تکمیل عملکرد (با موفقیت یا ناموفق) راهاندازی شود. هنگامی که تابع کامل می شود – صرف نظر از اینکه مقداری را برمی گرداند یا نه – بازگشت آن به وعده مرتبط خود عمل می کند و تابع از API مرورگر به صف وظایف جاوا اسکریپت منتقل می شود.
عامل کلیدی در پردازش ناهمزمان جاوا اسکریپت، حلقه رویداد آن است. حلقه رویداد به طور مداوم بررسی میکند که آیا پشته تماس و صف وظایف خالی هستند یا خیر، و مختصات زمانی که آن تماسهای ناهمزمان کامل شده باید به پشته تماس اصلی بازگردانده شوند.
حال بیایید جاوا اسکریپت را بررسی کنیم setTimeout
روشی برای مشاهده مدیریت روش ناهمزمان جاوا اسکریپت در عمل:
function a() {
b();
}
function b() {
setTimeout(() => {
console.log("After 5 secs");
}, 5000);
}
function c() {
console.log("Hello World");
}
a();
c();
بیایید از طریق کد عبور کنیم:
-
a
به پشته تماس می رود. -
b
‘ssetTimeout
فراخوانی به پشته تماس API مرورگر منتقل می شود. -
c
به پشته تماس می رود. -
c
‘sconsole.log
تماس به پشته تماس فشار می آورد. - وقتی که
setTimeout
روش تکمیل می شود، از API مرورگر به صف وظیفه منتقل می شود. - هر گونه توابع در فرآیند پشته تماس تا تکمیل.
- هنگامی که پشته تماس خالی می شود، حلقه رویداد آن را حرکت می دهد
setTimeout
تابع ‘s از صف وظیفه به پشته تماس برمی گردد.
مهندسان نرم افزار می توانند قابلیت های توسعه خود را از طریق استفاده از این روش های ناهمزمان جاوا اسکریپت گسترش دهند. اکنون که دیدیم روشهای ناهمزمان در زمان اجرا جاوا اسکریپت چگونه مدیریت میشوند، کاربرد آنها را با یک مثال کوتاه نشان میدهم.
برنامه های کاربردی دنیای واقعی: یک مثال چت بات
من اخیراً یک ربات چت مبتنی بر مرورگر توسعه داده ام. رفتار همزمان نامطلوب بود زیرا باعث می شد مکالمه به هم ریخته و کند به نظر برسد. راه حل من با برقراری ارتباط ناهمزمان با آن به مکالمه ای با سرعت خوب می رسد ChatGPT
API خارجی برای ارسال و دریافت پیام.
برای تسهیل ارتباط با ChatGPT
API، من یک سرور ساده Node.js با استفاده از آن ایجاد کردم OpenAI. سپس من اهرم جاوا اسکریپت ناهمزمان fetch
API که از وعده های برنامه ای برای ارائه راهی برای دسترسی و پردازش پاسخ ها استفاده می کند:
fetch(' {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: 'What is the weather like in Seattle?'
})
})
.then(response => response.json())
.then(data => {
console.log(data);
});
سرور ساده ما به صورت ناهمزمان آن را فراخوانی می کند ChatGPT
خدمات در حین ارائه انتقال پیام دو طرفه.
روش ناهمزمان دیگر I معمولا استفاده می شود setInterval()
. این تابع یک تایمر داخلی را فراهم می کند که متعاقباً یک تابع را به طور مکرر در هر بازه زمانی مشخصی فراخوانی می کند. استفاده كردن setInterval
، یک افکت تایپ را به رابط کاربری اضافه کردم و به کاربر اجازه دادم بداند طرف مقابل (ربات چت) در حال ایجاد پاسخ است:
// Creating loader function for bot
function loader(element) {
element.textContent = '';
// 300 ms allows for real-time responsiveness indicating other-party typing
loadInterval = setInterval(() => {
element.textContent += '.';
if (element.textContent === '....') {
element.textContent = '';
}
}, 300);
}
// Creating typing functionality
function typeText(element, text) {
let index = 0;
// 20 ms allows for real-time responsiveness to mimic chat typing
let interval = setInterval(() => {
if (index < text.length) {
element.innerHTML += text.charAt(index);
index++;
} else {
clearInterval(interval);
}
}, 20);
}
این دو بلوک ناهمزمان، یک مکالمه از هم گسیخته را به مکالمه ای تبدیل می کند که شرکت کنندگان در آن احساس مشارکت می کنند. اما پاسخگویی که جاوا اسکریپت ناهمزمان اجازه می دهد ممکن است یک عنصر کلیدی کمتر آشکار در زمینه های دیگر باشد.
نمونه های بیشتر جاوا اسکریپت ناهمزمان
زمانی که من وظیفه ایجاد یک افزونه وردپرس سفارشی را داشتم که به کاربران امکان می داد فایل های بزرگ را به صورت ناهمزمان آپلود کنند. من از یک کتابخانه AJAX استفاده کردم تا کاربر بتواند فایلهای خود را در پسزمینه آپلود کند، بدون اینکه منتظر بماند تا صفحه دوباره بارگذاری شود. این امکان تجربه کاربری بسیار روانتری را فراهم کرد و این برنامه موفقیت بزرگی داشت.
در یک مورد استفاده دیگر، یک وب سایت تجارت الکترونیک به دلیل تعداد زیاد تصاویری که باید بارگیری می کرد، با زمان بارگذاری کند مشکل داشت. برای سرعت بخشیدن به فرآیند، من یک تابع جاوا اسکریپت غیر همگام را پیاده سازی کردم (LazyLoading
) برای بارگیری هر تصویر به صورت ناهمزمان. این به وب سایت اجازه می داد تا سریعتر بارگذاری شود، زیرا همه تصاویر به طور همزمان بارگیری نمی شدند.
من همچنین روی پروژه ای کار کردم که شامل یک برنامه انتقال پول بود که API های مختلف رمزنگاری و پرداخت را ادغام می کرد. من نیاز داشتم که داده ها را از یک API خارجی بیرون بکشم، اما پاسخ API کمی طول کشید. برای اطمینان از اینکه برنامه در حین انتظار برای API متوقف نمیشود، یک تابع همگامسازی را پیادهسازی کردم که میتوانست برنامه را در حالی که منتظر پاسخ API بود، در حال اجرا نگه دارد و در نتیجه تجربه کاربری بهتری داشت.
روشهای ناهمزمان در پیادهسازی جاوا اسکریپت امکان عملکرد قدرتمند در خدمات کاربران نهایی را فراهم میکنند و کاهش سرعت رابط کاربری یا یخ زدگی را کاهش میدهند. به همین دلیل است که جاوا اسکریپت ناهمزمان برای حفظ کاربر در برنامههایی مانند Uber (اجرای فرآیندهای رزرو و پرداخت در پسزمینه)، توییتر (بارگیری آخرین توییتها در زمان واقعی) و Dropbox (همگامسازی و بهروز نگهداشتن فایلهای کاربران در دستگاهها بسیار مهم است. ).
بهعنوان یک توسعهدهنده، ممکن است نگران باشید که روشهای جاوا اسکریپت ناهمزمان آنطور که انتظار میرود در پشته تماس ظاهر نشوند – اما مطمئن باشید که اینطور هستند. میتوانید با اطمینان عملکرد ناهمزمان را در میان گزینههای خود در ارائه تجربیات کاربر برتر بگنجانید.
وبلاگ مهندسی تاپتال قدردانی خود را به محمد عاصم بلال برای بررسی محتوای فنی و نمونه کد ارائه شده در این مقاله.