وبورکر: رشتهٔ دوم جاوااسکریپت
خلاصهٔ کاملتر
نویسنده تو بلاگ Tighten با یه مثال آشنا شروع میکنه: فرم آپلود عکس. عکس خام گوشی راحت حدود ۸ مگابایت میشه، پس منطقیه که قبل از آپلود تو مرورگر کوچیکش کنی. ولی تا این کارو میکنی، تب یکی دو ثانیه خشک میشه؛ کلیکها جواب نمیدن و آپدیتهای زنده میایستن. علتش اینه که جاوااسکریپت فقط یه thread (رشتهٔ اجرا) داره و همون thread هم کد تو رو اجرا میکنه، هم کلیکها و رندر صفحه رو.
به گفتهٔ نویسنده یه تصور غلط رایج اینه که async/await این مشکل رو حل میکنه. اونها رشتهٔ جدید نمیسازن، فقط کار رو برای بعد تو همون صف زمانبندی میکنن. برای انتظار شبکه عالیه، ولی یه حلقهٔ سنگین روی پیکسلها هرجا اجرا شه بازم همون رشته رو بند میآره. برای کار CPU-سنگین به خط دوم نیاز داری و اون خط دوم Web Worker ـه.
ورکر یه رشتهٔ جدا با context جاوااسکریپت خودشه و دو قاعده داره. اول اینکه حافظه مشترک نیست و ارتباط فقط با postMessage انجام میشه؛ داده با structured clone کپی میشه (یعنی هر طرف نسخهٔ مستقل خودشو میگیره) و برای چیزهای سنگین مثل ArrayBuffer میتونی مالکیت رو transfer کنی تا کپی نشه. دوم اینکه ورکر به DOM دسترسی نداره، نه document داره نه window؛ پس محاسبه میکنه و تصمیم دربارهٔ صفحه میمونه برای رشتهٔ اصلی.
برای خود آپلود عکس، دو API کلیدی داخل ورکر هم کار میکنن: createImageBitmap که فایل رو decode میکنه و OffscreenCanvas که یه canvas بدون اتصال به صفحهست. ورکر فایل رو میگیره، با حفظ نسبت تصویر کوچیکش میکنه و با convertToBlob به WebP با کیفیت ۰.۸ تبدیلش میکنه:
const bitmap = await createImageBitmap(file)
const scale = Math.min(1, maxWidth / bitmap.width)
const canvas = new OffscreenCanvas(width, height)
const ctx = canvas.getContext('2d')
ctx.drawImage(bitmap, 0, 0, width, height)
const blob = await canvas.convertToBlob({ type: 'image/webp', quality: 0.8 })نتیجه اینه که همون عکس ۸ مگابایتی دیگه تب رو قفل نمیکنه و چیزی که به سرور میرسه حدود ۲۰۰ کیلوبایت WebP ـه، پس بکاند هم لازم نیست CPU خرج رسایز و تبدیل کنه. نویسنده آخر مقاله فرق Web Worker و Service Worker رو هم روشن میکنه: Service Worker یه پروکسی شبکهست برای کش و حالت آفلاین و push notification، نه ابزار محاسبه. برای کار سنگین CPU همون Web Worker گزینهست.
نکات کلیدی:
- async/await رشتهٔ جدید نمیسازه؛ فقط کار رو تو همون رشته زمانبندی میکنه
- ارتباط ورکر و رشتهٔ اصلی فقط با postMessage ـه و داده با structured clone کپی میشه
- برای ArrayBuffer بزرگ میتونی مالکیت رو transfer کنی، ولی File و Blob خودشون سبک رد و بدل میشن
- ورکر document و window نداره، ولی fetch، setTimeout، WebSocket، createImageBitmap و OffscreenCanvas رو داره
- اگه یه ورکر رو برای چند کار همزمان استفاده کنی، به هر پیام یه ID بده تا جوابها قاطی نشن




