شبکه سازی وب با کارگران ماژول

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

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

در پلتفرم وب، اصلی‌ترین اصل برای رشته‌بندی و موازی‌سازی Web Workers API است. Workers یک انتزاع سبک وزن در بالای رشته های سیستم عامل است که پیامی را که API را برای ارتباط بین رشته ای ارسال می کند، نشان می دهد. این می تواند در هنگام انجام محاسبات پرهزینه یا عملکرد بر روی مجموعه داده های بزرگ بسیار مفید باشد، و به نخ اصلی اجازه می دهد در حالی که عملیات گران قیمت را روی یک یا چند رشته پس زمینه انجام می دهد، روان اجرا شود.

در اینجا یک مثال معمولی از استفاده کارگر وجود دارد، که در آن یک اسکریپت کارگر به پیام‌هایی از رشته اصلی گوش می‌دهد و با ارسال پیام‌های خود به آن پاسخ می‌دهد:

page.js:

const worker = new Worker('worker.js');
worker.addEventListener('message', e => {
  console.log(e.data);
});
worker.postMessage('hello');

worker.js:

addEventListener('message', e => {
  if (e.data === 'hello') {
    postMessage('world');
  }
});

Web Worker API بیش از ده سال است که در اکثر مرورگرها موجود است. در حالی که این بدان معناست که کارگران از مرورگرهای عالی پشتیبانی می‌کنند و به خوبی بهینه‌سازی شده‌اند، همچنین به این معنی است که آنها مدت‌ها پیش از ماژول‌های جاوا اسکریپت پیش‌تر هستند. از آنجایی که هیچ سیستم ماژولی در زمان طراحی کارگران وجود نداشت، API برای بارگذاری کد در یک کارگر و نوشتن اسکریپت ها مشابه رویکردهای بارگذاری همزمان اسکریپت رایج در سال 2009 باقی مانده است.

تاریخچه: کارگران کلاسیک

سازنده Worker یک URL اسکریپت کلاسیک را می گیرد که نسبت به URL سند است. فوراً یک مرجع به نمونه کارگر جدید برمی‌گرداند، که یک رابط پیام‌رسانی و همچنین یک متد terminate() را نشان می‌دهد که بلافاصله کار را متوقف و نابود می‌کند.

const worker = new Worker('worker.js');

یک تابع importScripts() در وب کارگران برای بارگیری کد اضافی موجود است، اما اجرای worker را به منظور واکشی و ارزیابی هر اسکریپت متوقف می کند. همچنین اسکریپت ها را در محدوده جهانی مانند یک تگ <script> کلاسیک اجرا می کند، به این معنی که متغیرهای یک اسکریپت می توانند توسط متغیرهای موجود در اسکریپت دیگر بازنویسی شوند.

worker.js:

importScripts('greet.js');
// ^ could block for seconds
addEventListener('message', e => {
  postMessage(sayHello());
});

greet.js:

// global to the whole worker
function sayHello() {
  return 'world';
}

به همین دلیل، کارگران وب در طول تاریخ تأثیر بزرگی بر معماری یک برنامه کاربردی تحمیل کرده‌اند. توسعه‌دهندگان مجبور شده‌اند ابزارها و راه‌حل‌های هوشمندانه‌ای ایجاد کنند تا امکان استفاده از وب‌کارگرها را بدون دست کشیدن از شیوه‌های توسعه مدرن فراهم کنند. به عنوان مثال، باندلرهایی مانند webpack یک پیاده‌سازی بارگذار ماژول کوچک را در کد تولید شده تعبیه می‌کنند که از importScripts() برای بارگذاری کد استفاده می‌کند، اما ماژول‌ها را در توابع پیچیده می‌کند تا از برخورد متغیرها جلوگیری کند و واردات و صادرات وابستگی را شبیه‌سازی کند.

کارگران ماژول را وارد کنید

یک حالت جدید برای کارگران وب با مزایای ارگونومی و عملکرد ماژول‌های جاوا اسکریپت در Chrome 80 ارسال می‌شود که ماژول کارگران نام دارد. سازنده Worker اکنون یک گزینه جدید {type:"module"} را می پذیرد که بارگیری و اجرای اسکریپت را برای مطابقت با <script type="module"> تغییر می دهد.

const worker = new Worker('worker.js', {
  type: 'module'
});

از آنجایی که کارگران ماژول ماژول های استاندارد جاوا اسکریپت هستند، می توانند از دستورات import و export استفاده کنند. مانند همه ماژول‌های جاوا اسکریپت، وابستگی‌ها فقط یک بار در یک زمینه مشخص (رشته اصلی، کارگر و غیره) اجرا می‌شوند و همه واردات‌های آینده به نمونه ماژول قبلاً اجرا شده ارجاع می‌دهند. بارگذاری و اجرای ماژول های جاوا اسکریپت نیز توسط مرورگرها بهینه شده است. وابستگی های یک ماژول را می توان قبل از اجرای ماژول بارگذاری کرد، که اجازه می دهد کل درختان ماژول به صورت موازی بارگذاری شوند. بارگذاری ماژول همچنین کدهای تجزیه شده را در حافظه پنهان ذخیره می کند، به این معنی که ماژول هایی که در رشته اصلی و در یک کارگر استفاده می شوند فقط یک بار باید تجزیه شوند.

انتقال به ماژول های جاوا اسکریپت همچنین استفاده از واردات پویا را برای کد بارگیری تنبل بدون مسدود کردن اجرای کارگر امکان پذیر می کند. واردات پویا بسیار واضح تر از استفاده از importScripts() برای بارگیری وابستگی ها است، زیرا صادرات ماژول وارد شده به جای تکیه بر متغیرهای سراسری برگردانده می شود.

worker.js:

import { sayHello } from './greet.js';
addEventListener('message', e => {
  postMessage(sayHello());
});

greet.js:

import greetings from './data.js';
export function sayHello() {
  return greetings.hello;
}

برای اطمینان از عملکرد عالی، روش قدیمی importScripts() در ماژول کارگران موجود نیست. تغییر کارگران به استفاده از ماژول های جاوا اسکریپت به این معنی است که همه کدها در حالت سخت بارگذاری می شوند. تغییر قابل توجه دیگر این است که مقدار this در محدوده سطح بالای یک ماژول جاوا اسکریپت undefined است، در حالی که در کارگران کلاسیک این مقدار محدوده جهانی کارگر است. خوشبختانه، همیشه یک self جهانی وجود داشته است که مرجعی را به دامنه جهانی ارائه می دهد. این در همه انواع کارگران از جمله کارگران خدماتی و همچنین در DOM موجود است.

کارگران را با modulepreload پیش بار کنید

یکی از بهبودهای عملکرد قابل توجهی که با کارگران ماژول همراه است، توانایی پیش بارگیری کارگران و وابستگی های آنها است. با ماژول‌کاران، اسکریپت‌ها به‌عنوان ماژول‌های استاندارد جاوا اسکریپت بارگیری و اجرا می‌شوند، به این معنی که می‌توان آن‌ها را از قبل بارگذاری کرد و حتی با استفاده از modulepreload از قبل تجزیه کرد:

<!-- preloads worker.js and its dependencies: -->
<link rel="modulepreload" href="worker.js">

<script>
  addEventListener('load', () => {
    // our worker code is likely already parsed and ready to execute!
    const worker = new Worker('worker.js', { type: 'module' });
  });
</script>

ماژول های از پیش بارگذاری شده نیز می توانند توسط thread اصلی و کارگران ماژول استفاده شوند. این برای ماژول هایی که در هر دو زمینه وارد می شوند مفید است، یا در مواردی که نمی توان از قبل دانست که آیا یک ماژول در رشته اصلی یا کارگر استفاده می شود.

پیش از این، گزینه‌های موجود برای بارگذاری پیش‌نویس اسکریپت‌های وب کارگر محدود و لزوماً قابل اعتماد نبودند. کارگران کلاسیک نوع منبع "کارگر" خود را برای بارگذاری اولیه داشتند، اما هیچ مرورگری <link rel="preload" as="worker"> را پیاده سازی نکرد. در نتیجه، تکنیک اولیه موجود برای پیش بارگیری کارگران وب استفاده از <link rel="prefetch"> بود که کاملاً بر حافظه پنهان HTTP متکی بود. هنگامی که در ترکیب با هدرهای ذخیره سازی صحیح استفاده می شود، این امکان را فراهم می کند که از نمونه سازی کارگر برای دانلود اسکریپت کارگر جلوگیری شود. با این حال، بر خلاف modulepreload این تکنیک از وابستگی های پیش بارگذاری یا پیش تجزیه پشتیبانی نمی کند.

کارگران مشترک چطور؟

کارگران مشترک با پشتیبانی از ماژول‌های جاوا اسکریپت از Chrome 83 به‌روزرسانی شده‌اند. مانند کارگران اختصاصی، ساختن یک کارگر مشترک با گزینه {type:"module"} اکنون اسکریپت کارگر را به‌عنوان یک ماژول بارگیری می‌کند تا یک اسکریپت کلاسیک:

const worker = new SharedWorker('/worker.js', {
  type: 'module'
});

قبل از پشتیبانی از ماژول های جاوا اسکریپت، سازنده SharedWorker() فقط یک URL و یک آرگومان name اختیاری را انتظار داشت. این برای استفاده کلاسیک کارگر مشترک به کار خود ادامه خواهد داد. با این حال، ایجاد کارگران مشترک ماژول نیازمند استفاده از آرگومان options جدید است. گزینه های موجود مانند گزینه های یک کارگر اختصاصی هستند، از جمله گزینه name که جایگزین آرگومان name قبلی می شود.

در مورد کارگر خدماتی چطور؟

مشخصات کارگر سرویس قبلاً به‌روزرسانی شده است تا از پذیرش یک ماژول جاوا اسکریپت به عنوان نقطه ورودی با استفاده از گزینه {type:"module"} مانند کارگران ماژول پشتیبانی کند، اما این تغییر هنوز در مرورگرها اعمال نشده است. هنگامی که این اتفاق افتاد، می‌توان یک سرویس‌کار را با استفاده از یک ماژول جاوا اسکریپت با استفاده از کد زیر نمونه‌سازی کرد:

navigator.serviceWorker.register('/sw.js', {
  type: 'module'
});

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

منابع اضافی و مطالعه بیشتر

،

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

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

در پلتفرم وب، اصلی‌ترین اصل برای رشته‌بندی و موازی‌سازی Web Workers API است. Workers یک انتزاع سبک وزن در بالای رشته های سیستم عامل است که پیامی را که API را برای ارتباط بین رشته ای ارسال می کند، نشان می دهد. این می تواند در هنگام انجام محاسبات پرهزینه یا عملکرد بر روی مجموعه داده های بزرگ بسیار مفید باشد، و به نخ اصلی اجازه می دهد در حالی که عملیات گران قیمت را روی یک یا چند رشته پس زمینه انجام می دهد، روان اجرا شود.

در اینجا یک مثال معمولی از استفاده کارگر وجود دارد، که در آن یک اسکریپت کارگر به پیام‌هایی از رشته اصلی گوش می‌دهد و با ارسال پیام‌های خود به آن پاسخ می‌دهد:

page.js:

const worker = new Worker('worker.js');
worker.addEventListener('message', e => {
  console.log(e.data);
});
worker.postMessage('hello');

worker.js:

addEventListener('message', e => {
  if (e.data === 'hello') {
    postMessage('world');
  }
});

Web Worker API بیش از ده سال است که در اکثر مرورگرها موجود است. در حالی که این بدان معناست که کارگران از مرورگرهای عالی پشتیبانی می‌کنند و به خوبی بهینه‌سازی شده‌اند، همچنین به این معنی است که آنها مدت‌ها پیش از ماژول‌های جاوا اسکریپت پیش‌تر هستند. از آنجایی که هیچ سیستم ماژولی در زمان طراحی کارگران وجود نداشت، API برای بارگذاری کد در یک کارگر و نوشتن اسکریپت ها مشابه رویکردهای بارگذاری همزمان اسکریپت رایج در سال 2009 باقی مانده است.

تاریخچه: کارگران کلاسیک

سازنده Worker یک URL اسکریپت کلاسیک را می گیرد که نسبت به URL سند است. فوراً یک مرجع به نمونه کارگر جدید برمی‌گرداند، که یک رابط پیام‌رسانی و همچنین یک متد terminate() را نشان می‌دهد که بلافاصله کار را متوقف و نابود می‌کند.

const worker = new Worker('worker.js');

یک تابع importScripts() در وب کارگران برای بارگیری کد اضافی موجود است، اما اجرای worker را به منظور واکشی و ارزیابی هر اسکریپت متوقف می کند. همچنین اسکریپت ها را در محدوده جهانی مانند یک تگ <script> کلاسیک اجرا می کند، به این معنی که متغیرهای یک اسکریپت می توانند توسط متغیرهای موجود در اسکریپت دیگر بازنویسی شوند.

worker.js:

importScripts('greet.js');
// ^ could block for seconds
addEventListener('message', e => {
  postMessage(sayHello());
});

greet.js:

// global to the whole worker
function sayHello() {
  return 'world';
}

به همین دلیل، کارگران وب در طول تاریخ تأثیر بزرگی بر معماری یک برنامه کاربردی تحمیل کرده‌اند. توسعه‌دهندگان مجبور شده‌اند ابزارها و راه‌حل‌های هوشمندانه‌ای ایجاد کنند تا امکان استفاده از وب‌کارگرها را بدون دست کشیدن از شیوه‌های توسعه مدرن فراهم کنند. به عنوان مثال، باندلرهایی مانند webpack یک پیاده‌سازی بارگذار ماژول کوچک را در کد تولید شده تعبیه می‌کنند که از importScripts() برای بارگذاری کد استفاده می‌کند، اما ماژول‌ها را در توابع پیچیده می‌کند تا از برخورد متغیرها جلوگیری کند و واردات و صادرات وابستگی را شبیه‌سازی کند.

کارگران ماژول را وارد کنید

یک حالت جدید برای کارگران وب با مزایای ارگونومی و عملکرد ماژول‌های جاوا اسکریپت در Chrome 80 ارسال می‌شود که ماژول کارگران نام دارد. سازنده Worker اکنون یک گزینه جدید {type:"module"} را می پذیرد که بارگیری و اجرای اسکریپت را برای مطابقت با <script type="module"> تغییر می دهد.

const worker = new Worker('worker.js', {
  type: 'module'
});

از آنجایی که کارگران ماژول ماژول های استاندارد جاوا اسکریپت هستند، می توانند از دستورات import و export استفاده کنند. مانند همه ماژول‌های جاوا اسکریپت، وابستگی‌ها فقط یک بار در یک زمینه مشخص (رشته اصلی، کارگر و غیره) اجرا می‌شوند و همه واردات‌های آینده به نمونه ماژول قبلاً اجرا شده ارجاع می‌دهند. بارگذاری و اجرای ماژول های جاوا اسکریپت نیز توسط مرورگرها بهینه شده است. وابستگی های یک ماژول را می توان قبل از اجرای ماژول بارگذاری کرد، که اجازه می دهد کل درختان ماژول به صورت موازی بارگذاری شوند. بارگذاری ماژول همچنین کدهای تجزیه شده را در حافظه پنهان ذخیره می کند، به این معنی که ماژول هایی که در رشته اصلی و در یک کارگر استفاده می شوند فقط یک بار باید تجزیه شوند.

انتقال به ماژول های جاوا اسکریپت همچنین استفاده از واردات پویا را برای کد بارگیری تنبل بدون مسدود کردن اجرای کارگر امکان پذیر می کند. واردات پویا بسیار واضح تر از استفاده از importScripts() برای بارگیری وابستگی ها است، زیرا صادرات ماژول وارد شده به جای تکیه بر متغیرهای سراسری برگردانده می شود.

worker.js:

import { sayHello } from './greet.js';
addEventListener('message', e => {
  postMessage(sayHello());
});

greet.js:

import greetings from './data.js';
export function sayHello() {
  return greetings.hello;
}

برای اطمینان از عملکرد عالی، روش قدیمی importScripts() در ماژول کارگران موجود نیست. تغییر کارگران به استفاده از ماژول های جاوا اسکریپت به این معنی است که همه کدها در حالت سخت بارگذاری می شوند. تغییر قابل توجه دیگر این است که مقدار this در محدوده سطح بالای یک ماژول جاوا اسکریپت undefined است، در حالی که در کارگران کلاسیک این مقدار محدوده جهانی کارگر است. خوشبختانه، همیشه یک self جهانی وجود داشته است که مرجعی را به دامنه جهانی ارائه می دهد. این در همه انواع کارگران از جمله کارگران خدماتی و همچنین در DOM موجود است.

کارگران را با modulepreload پیش بار کنید

یکی از بهبودهای عملکرد قابل توجهی که با کارگران ماژول همراه است، توانایی پیش بارگیری کارگران و وابستگی های آنها است. با ماژول‌کاران، اسکریپت‌ها به‌عنوان ماژول‌های استاندارد جاوا اسکریپت بارگیری و اجرا می‌شوند، به این معنی که می‌توان آن‌ها را از قبل بارگذاری کرد و حتی با استفاده از modulepreload از قبل تجزیه کرد:

<!-- preloads worker.js and its dependencies: -->
<link rel="modulepreload" href="worker.js">

<script>
  addEventListener('load', () => {
    // our worker code is likely already parsed and ready to execute!
    const worker = new Worker('worker.js', { type: 'module' });
  });
</script>

ماژول های از پیش بارگذاری شده نیز می توانند توسط thread اصلی و کارگران ماژول استفاده شوند. این برای ماژول هایی که در هر دو زمینه وارد می شوند مفید است، یا در مواردی که نمی توان از قبل دانست که آیا یک ماژول در رشته اصلی یا کارگر استفاده می شود.

پیش از این، گزینه‌های موجود برای بارگذاری پیش‌نویس اسکریپت‌های وب کارگر محدود و لزوماً قابل اعتماد نبودند. کارگران کلاسیک نوع منبع "کارگر" خود را برای بارگذاری اولیه داشتند، اما هیچ مرورگری <link rel="preload" as="worker"> را پیاده سازی نکرد. در نتیجه، تکنیک اولیه موجود برای پیش بارگیری کارگران وب استفاده از <link rel="prefetch"> بود که کاملاً بر حافظه پنهان HTTP متکی بود. هنگامی که در ترکیب با هدرهای ذخیره سازی صحیح استفاده می شود، این امکان را فراهم می کند که از نمونه سازی کارگر برای دانلود اسکریپت کارگر جلوگیری شود. با این حال، بر خلاف modulepreload این تکنیک از وابستگی های پیش بارگذاری یا پیش تجزیه پشتیبانی نمی کند.

کارگران مشترک چطور؟

کارگران مشترک با پشتیبانی از ماژول‌های جاوا اسکریپت از Chrome 83 به‌روزرسانی شده‌اند. مانند کارگران اختصاصی، ساختن یک کارگر مشترک با گزینه {type:"module"} اکنون اسکریپت کارگر را به‌عنوان یک ماژول بارگیری می‌کند تا یک اسکریپت کلاسیک:

const worker = new SharedWorker('/worker.js', {
  type: 'module'
});

قبل از پشتیبانی از ماژول های جاوا اسکریپت، سازنده SharedWorker() فقط یک URL و یک آرگومان name اختیاری را انتظار داشت. این برای استفاده کلاسیک کارگر مشترک به کار خود ادامه خواهد داد. با این حال، ایجاد کارگران مشترک ماژول نیازمند استفاده از آرگومان options جدید است. گزینه های موجود مانند گزینه های یک کارگر اختصاصی هستند، از جمله گزینه name که جایگزین آرگومان name قبلی می شود.

در مورد کارگر خدماتی چطور؟

مشخصات کارگر سرویس قبلاً به‌روزرسانی شده است تا از پذیرش یک ماژول جاوا اسکریپت به عنوان نقطه ورودی با استفاده از گزینه {type:"module"} مانند کارگران ماژول پشتیبانی کند، اما این تغییر هنوز در مرورگرها اعمال نشده است. هنگامی که این اتفاق افتاد، می‌توان یک سرویس‌کار را با استفاده از یک ماژول جاوا اسکریپت با استفاده از کد زیر نمونه‌سازی کرد:

navigator.serviceWorker.register('/sw.js', {
  type: 'module'
});

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

منابع اضافی و مطالعه بیشتر