Faragiri

همهٔ زبان‌ها

آموزش نود جی‌اس (Node.js) بک‌اند

جاوااسکریپت شما روی یک رشته اجرا می‌شود، پس هر سطری که طولانی حساب می‌کند همه درخواست‌های دیگر را متوقف می‌کند.

۴بخش
۳دقیقه خواندن
۴عمق

یک رشته، یک حلقه

ترتیبی که حلقه رویداد در هر دور طی می‌کند

این حلقه به همان جایی برمی‌گردد که شروع شده، و هر کار طولانی در هر ایستگاه، کل دور را متوقف می‌کند.

یک دور

  • ۰۱تایمرهاهر چیزی که زمانش رسیده، به ترتیب سررسید
  • ۰۲کال‌بک‌های معوقچند کال‌بک سیستمی که از دور قبل مانده‌اند
  • ۰۳نظرسنجی ورودی و خروجیجایی که بیشتر وقت یک سرور سالم می‌گذرد
  • ۰۴بررسیکال‌بک‌های بلافاصله، پیش از دور بعدی تایمرها
  • ۰۵بستن اتصال‌هاسوکت‌ها و جریان‌هایی که بسته می‌شوند، و دوباره از اول
  1. ۰۱تایمرهاهر چیزی که زمانش رسیده، به ترتیب سررسید
  2. ۰۲کال‌بک‌های معوقچند کال‌بک سیستمی که از دور قبل مانده‌اند
  3. ۰۳نظرسنجی ورودی و خروجیجایی که بیشتر وقت یک سرور سالم می‌گذرد
  4. ۰۴بررسیکال‌بک‌های بلافاصله، پیش از دور بعدی تایمرها
  5. ۰۵بستن اتصال‌هاسوکت‌ها و جریان‌هایی که بسته می‌شوند، و دوباره از اول

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

Node کد جاوااسکریپت شما را روی یک رشته اجرا می‌کند. کارهای ورودی و خروجی جای دیگری انجام می‌شوند و نتیجه‌شان بعدا به همان رشته برمی‌گردد، اما هر سطری که خودش طولانی حساب می‌کند، همه درخواست‌های دیگر را متوقف می‌کند.

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

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

کار سنگین کجا باید برود

سه راه هست و انتخاب میانشان به شکل کار بستگی دارد. برای کاری که چند صد میلی‌ثانیه پردازنده می‌خواهد، رشته‌های کارگر در خود Node هستند و همان فرایند را نگه می‌دارند. برای کاری که ثانیه‌ها طول می‌کشد، یک صف و یک فرایند کارگر جدا درست است، تا درخواست کاربر بلافاصله جواب بگیرد.

و برای کاری که فقط منتظر است، مثل چند درخواست شبکه، هیچ‌کدام لازم نیست؛ همان مدل ناهمگام کارش را می‌کند و این دقیقا همان چیزی است که Node را برای دروازه‌های شبکه مناسب کرده: کال‌بک، پرامیس، و انتظار روی نتیجه.

چند هسته، چند فرایند

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

و همین‌جا یک نکته که زیاد از قلم می‌افتد: هر حالتی که در حافظه یک فرایند نگه دارید، در فرایندهای دیگر وجود ندارد. نشست در حافظه، کش در حافظه، و شمارنده محدودیت نرخ همه با اضافه شدن فرایند دوم می‌شکنند و جایشان یک انبار مشترک است.

جایی که کار گیر می‌کند، نصب وابستگی‌هاست

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

ابزار، و سالی که این حرف درست است

در سال ۲۰۲۶ نسخه‌ای که باید رویش باشید Node.js 24 است، که خط پشتیبانی بلندمدت است و جانشین Node.js 22 شد؛ متن‌باز و رایگان است. اجراکننده آزمون در خود Node هست و برای بیشتر پروژه‌ها جای یک کتابخانه آزمون جداگانه را گرفته. برای دیدن اینکه کدام تابع رشته را بلوکه کرده، پروفایلر داخلی با یک پرچم روشن می‌شود و خروجی‌اش را می‌شود در بازرس مرورگر خواند.

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

بالای این