در منظر توسعه فرانتاند مدرن، رابط کاربری روان یک شرط غیرقابل مذاکره است. ما اغلب این شعار را میشنویم: «رشته اصلی را آزاد نگه دارید.» اما وقتی با یک تبدیل دادههای پیچیده، یک عملیات رمزنگاری سنگین، یا یک وظیفه بزرگ تجزیه JSON روبرو هستید چه میشود؟ اگر این منطق را روی رشته اصلی اجرا کنید، چرخه رندر برنامه شما متوقف شده و منجر به افت فریمها، دکمههای غیرپاسخگو و تجربه کاربری ضعیفی میشود که به آن «جنگ» (Jank) میگویند.
اینجاست که Web Workers وارد عمل میشوند. با بهرهگیری از توانایی مرورگر برای اجرای اسکریپتها در رشتههای پسزمینه، میتوانید حتی تحت بار محاسباتی سنگین، یک رابط کاربری پاسخگو را حفظ کنید. این پست بررسی میکند که چگونه میتوان به طور مؤثر از Web Workers برای انجام کارهای سنگین استفاده کرد تا اطمینان حاصل شود برنامههای شما سریع و حرفهای باقی میمانند.
درک ماهیت تکرشتهای رشته اصلی
رشته اصلی مرورگر مسئول اجرای جاوااسکریپت، مدیریت تعاملات کاربر (کلیکها، اسکرولها) و مدیریت Document Object Model (DOM) است. اگرچه قدرتمند است، اما به صورت همزمان (سینکرون) عمل میکند. وقتی یک حلقه طولانیمدت یا یک الگوریتم پیچیده را اجرا میکنید، مرورگر نمیتواند صفحه را بهروزرسانی کند یا به رویدادهای ورودی پاسخ دهد تا زمانی که آن کد به پایان برسد.
Web Workers با ایجاد رشتههای جداگانهای که به صورت مستقل از رشته اصلی اجرا میشوند، راهحلی ارائه میدهند. این کارگران همان سیاست مبدأ (origin policy) را به اشتراک میگذارند و میتوانند محاسبات سنگین را بدون مسدود کردن رابط کاربری انجام دهند. آنها از طریق یک سیستم ارسال پیام با رشته اصلی ارتباط برقرار میکنند که یکپارچگی دادهها را تضمین کرده و از شرایط رقابتی (race conditions) جلوگیری میکند.
پیادهسازی اولین Web Worker شما
پیادهسازی یک Web Worker ساده است. شما یک فایل جاوااسکریپت جداگانه ایجاد میکنید که منطق کارگر را در خود نگه میدارد. بیایید فرض کنیم ما یک محاسبه ریاضی سنگین داریم که میخواهیم اجرا کنیم. ما فایلی به نام math-worker.js ایجاد خواهیم کرد.
// math-worker.js
self.onmessage = function(e) {
const data = e.data;
const result = heavyComputation(data.number);
// ارسال نتیجه به رشته اصلی
self.postMessage(result);
};
function heavyComputation(num) {
let result = 0;
for (let i = 0; i < 1e9; i++) {
result += Math.sqrt(i);
}
return num + result;
}
سپس، در کد برنامه اصلی خود (مثلاً app.js)، کارگر را نمونهسازی کرده و دادهها را به آن ارسال میکنید.
// app.js
const worker = new Worker('math-worker.js');
// گوش دادن به پیامهای ارسالی از کارگر
worker.onmessage = function(e) {
console.log('کارگر گفت: ', e.data);
};
// ارسال داده به کارگر
worker.postMessage({ number: 42 });
در این مثال، رشته اصلی یک پیام را به کارگر ارسال میکند. کارگر پیام را از طریق رویداد onmessage دریافت میکند، محاسبه را انجام میدهد و نتیجه را برمیگرداند. رشته اصلی در حین انجام این محاسبه آزاد است تا انیمیشنها را رندر کند و کلیکها را مدیریت نماید.
بهترین شیوهها و بهینهسازی
اگرچه Web Workers قدرتمند هستند، اما راهحل جادویی نیستند. ملاحظات خاصی وجود دارد که باید برای استفاده مؤثر از آنها در نظر بگیرید.
از دسترسی به DOM خودداری کنید
Web Workers به DOM دسترسی ندارند. شما نمیتوانید اشیاء document یا پنجره را از داخل یک کارگر دستکاری کنید. این موضوع به طراحی آگاهانه است تا از شرایط رقابتی جلوگیری شود. اگر نیاز دارید بر اساس نتیجه، رابط کاربری را بهروزرسانی کنید، دادهها را به رشته اصلی بازگردانید و اجازه دهید رشته اصلی بهروزرسانی DOM را انجام دهد.
بار انتقال داده را به حداقل برسانید
ارتباط بین رشتهها شامل سریالسازی و دسریالسازی دادهها است. ارسال مقادیر زیاد داده به جلو و عقب میتواند تأخیر ایجاد کند. برای کاهش این مشکل، از اشیای قابل انتقال (Transferable Objects) در صورت امکان استفاده کنید. برای مثال، هنگام ارسال یک ArrayBuffer، میتوانید مالکیت بافر را به کارگر منتقل کنید و از عملیات کپی پرهزینه جلوگیری نمایید.
// انتقال کارآمد دادههای بزرگ
const buffer = new ArrayBuffer(1024 * 1024);
worker.postMessage(buffer, [buffer]);
از Web Workers برای وظایف وابسته به CPU، نه I/O استفاده کنید
Web Workers در وظایف سنگین CPU مانند پردازش تصویر، تحلیل داده و رمزنگاری عالی عمل میکنند. با این حال، برای وظایف وابسته به I/O مانند درخواستهای شبکه، رشته اصلی ممکن است از قبل درخواستهای ناهمگام را به طور کارآمد مدیریت کند. کارگران را برای عملیاتی که واقعاً حلقه رندر را مسدود میکنند، ذخیره کنید.
نتیجهگیری
پیادهسازی Web Workers یک مهارت حیاتی برای توسعهدهندگان فرانتاند متوسط و پیشرفته است که هدفشان ساخت وباپلیکیشنهای با عملکرد بالا است. با انتقال پردازش سنگین جاوااسکریپت به رشتههای پسزمینه، اطمینان حاصل میکنید که برنامه شما پاسخگو باقی میماند و تجربه کاربری بینقصی ارائه میدهد. به یاد داشته باشید که مرزهای محیط کارگر را رعایت کنید، انتقال داده را بهینهسازی کنید و از کارگران به صورت استراتژیک برای وظایف وابسته به CPU استفاده نمایید. با به کارگیری این شیوهها، میتوانید پتانسیل کامل عملکرد برنامه خود را آزاد کنید.