Code & Life
Photo
توی دل Event Loop چه خبره؟
ایونت لوپ یه مکانیزم هوشمندانه در Node.js هست که کارهای غیرهمزمان رو مدیریت میکنه. وقتی کدهای مختلف رو مینویسیم و منتظر نتیجه اونها میمونیم، Event Loop بهطور خودکار این کارها رو پشتصحنه مدیریت میکنه و ما رو از نگرانیهای پیچیده دور نگه میداره. ولی این روند خیلی پیچیدهتر از چیزیه که به نظر میاد. توی این توضیحات، من سعی میکنم ساده و خودمونی براتون توضیح بدم که چطور این اتفاقها میافتن.
خلاصهای از عملکرد Event Loop
ایونت لوپ از چندین فاز یا مرحله مختلف تشکیل شده که هرکدوم مسئول انجام یه سری کار خاص هستن. وقتی Event Loop وارد هر فاز میشه، یه صف FIFO (اول وارد، اول خارج) رو اجرا میکنه. یعنی کالبکها رو یکییکی از صف میگیره و اجرا میکنه. وقتی فاز تموم شد، میره به فاز بعدی.
به زبان ساده، هر مرحله مثل یک ایستگاه توی یک قطار هست. هر ایستگاه کار خودش رو انجام میده و وقتی تموم شد، قطار به ایستگاه بعدی میره. این چرخه ادامه پیدا میکنه تا تمام کارها انجام بشه.
مراحل مختلف Event Loop:
۱. Timers (تایمرها)
اولین مرحله، مرحلهی تایمر هاست. توی این قسمت، توابعی که با setTimeout() یا setInterval() تنظیم کردیم، اجرا میشن. یعنی وقتی زمان مشخصی که براشون تعیین کردیم تموم بشه، این توابع شروع به کار میکنن. البته، زمان دقیق اجرای این توابع ممکنه تحت تأثیر کدهای دیگه هم قرار بگیره. پس در واقع، Event Loop نمیتونه تضمین کنه که دقیقاً در زمان تعیینشده اجرا بشن.
مثال: فرض کن یه تایمر ۵ ثانیهای گذاشتی که بعد از ۵ ثانیه یه پیام رو چاپ کنه. وقتی تایم تموم میشه، این تابع وارد صف تایمرها میشه و بعد اجرا میشه.
۲. Pending Callbacks (کالبکهای معلق)
حالا، مرحلهی بعدی برای اونهایی هست که توابعی رو اجرا کردن که به نوعی با ورودی یا خروجی (I/O) سروکار دارن و منتظر کالبک هستن. مثلاً اگر یک درخواست HTTP به یه سرور دادهایم و منتظر جواب هستیم، وقتی سرور جواب داد، اینجا کالبک اجرا میشه.
مثال: فرض کن یک فایل رو از دیسک میخونی. وقتی خونده شد، کالبک باید اجرا بشه و به تو بگه که فایل آماده است. این مرحله مسئولیت اون رو به عهده داره.
۳. Idle, Prepare (آمادهسازی)
این مرحله بیشتر به کارهای داخلی Node.js مربوط میشه و معمولاً در برنامههای معمولی خیلی بهش نمیپردازیم. اما به طور کلی، Node.js این مرحله رو برای آمادهسازی خودش انجام میده تا وارد مراحل بعدی بشه.
۴. Poll (پُل)
مرحلهی پُل، قلب تپندهی Event Loop هست. اینجا، Node.js منتظره که ببینه آیا اتفاقی میافته یا نه. یعنی در اینجا منتظره تا رویدادی بیفته، مثل دریافت یک درخواست جدید، اتصال جدید، یا هر چیز دیگهای که به صورت غیرهمزمان نیاز به پردازش داشته باشه.
اگر رویدادی نباشه، ممکنه یه مدت وایسه یا حتی به فازهای بعدی بره. این مرحله بهطور کلی مسئول نظارت بر وقوع رویدادهای جدید هست.
مثال: فرض کن یک کاربر یه درخواست ارسال کرده و حالا Node.js منتظره که جواب از دیتابیس بیاد. تا وقتی که جواب نیاد، هیچکاری نمیکنه و منتظر میمونه.
۵. Check (چک)
بعد از مرحلهی پُل، نوبت به توابعی میرسه که با setImmediate() تنظیم شدهاند. این توابع بعد از مرحلهی پُل و قبل از مرحلهی Close Callbacks اجرا میشن.
این مرحله به نوعی نظارت میکنه که اگه هنوز چیزی منتظره نباشه، توابعی که باید فوراً بعد از پُل اجرا بشن، اجرا بشن.
۶. Close Callbacks (کالبکهای بستهشدن)
مرحلهی آخر، مرحلهی کالبکهای بستهشدن هست. اینجا، توابعی که نیاز به اجرا شدن بعد از بسته شدن چیزی دارن، اجرا میشن. مثلاً وقتی یک سوکت بسته میشه و باید کالبک اجرا بشه، اینجا انجام میشه.
مثال: فرض کن یک اتصال شبکه بسته میشه و باید یه فعالیت خاصی مثل بستن فایلها یا آزادسازی منابع انجام بشه. این مرحله هم همون کار رو میکنه.
نتیجهگیری :
حالا که این مراحل رو با هم مرور کردیم، متوجه شدیم که چطور Node.js از این فازها برای مدیریت کارهای غیر همزمان استفاده میکنه. این فرآیند پیچیده، ولی در عین حال خیلی کارآمد هست و باعث میشه که Node.js بتونه به طور همزمان تعداد زیادی از کارها رو انجام بده بدون اینکه نیاز به چندین نخ (thread) داشته باشه.
اینکه بدونید Event Loop چطور کار میکنه، بهتون کمک میکنه که درک بهتری از نحوه عملکرد Node.js داشته باشید و بتونید برنامههاتون رو بهینهتر بنویسید.
@erfuuan_dev
ایونت لوپ یه مکانیزم هوشمندانه در Node.js هست که کارهای غیرهمزمان رو مدیریت میکنه. وقتی کدهای مختلف رو مینویسیم و منتظر نتیجه اونها میمونیم، Event Loop بهطور خودکار این کارها رو پشتصحنه مدیریت میکنه و ما رو از نگرانیهای پیچیده دور نگه میداره. ولی این روند خیلی پیچیدهتر از چیزیه که به نظر میاد. توی این توضیحات، من سعی میکنم ساده و خودمونی براتون توضیح بدم که چطور این اتفاقها میافتن.
خلاصهای از عملکرد Event Loop
ایونت لوپ از چندین فاز یا مرحله مختلف تشکیل شده که هرکدوم مسئول انجام یه سری کار خاص هستن. وقتی Event Loop وارد هر فاز میشه، یه صف FIFO (اول وارد، اول خارج) رو اجرا میکنه. یعنی کالبکها رو یکییکی از صف میگیره و اجرا میکنه. وقتی فاز تموم شد، میره به فاز بعدی.
به زبان ساده، هر مرحله مثل یک ایستگاه توی یک قطار هست. هر ایستگاه کار خودش رو انجام میده و وقتی تموم شد، قطار به ایستگاه بعدی میره. این چرخه ادامه پیدا میکنه تا تمام کارها انجام بشه.
مراحل مختلف Event Loop:
۱. Timers (تایمرها)
اولین مرحله، مرحلهی تایمر هاست. توی این قسمت، توابعی که با setTimeout() یا setInterval() تنظیم کردیم، اجرا میشن. یعنی وقتی زمان مشخصی که براشون تعیین کردیم تموم بشه، این توابع شروع به کار میکنن. البته، زمان دقیق اجرای این توابع ممکنه تحت تأثیر کدهای دیگه هم قرار بگیره. پس در واقع، Event Loop نمیتونه تضمین کنه که دقیقاً در زمان تعیینشده اجرا بشن.
مثال: فرض کن یه تایمر ۵ ثانیهای گذاشتی که بعد از ۵ ثانیه یه پیام رو چاپ کنه. وقتی تایم تموم میشه، این تابع وارد صف تایمرها میشه و بعد اجرا میشه.
۲. Pending Callbacks (کالبکهای معلق)
حالا، مرحلهی بعدی برای اونهایی هست که توابعی رو اجرا کردن که به نوعی با ورودی یا خروجی (I/O) سروکار دارن و منتظر کالبک هستن. مثلاً اگر یک درخواست HTTP به یه سرور دادهایم و منتظر جواب هستیم، وقتی سرور جواب داد، اینجا کالبک اجرا میشه.
مثال: فرض کن یک فایل رو از دیسک میخونی. وقتی خونده شد، کالبک باید اجرا بشه و به تو بگه که فایل آماده است. این مرحله مسئولیت اون رو به عهده داره.
۳. Idle, Prepare (آمادهسازی)
این مرحله بیشتر به کارهای داخلی Node.js مربوط میشه و معمولاً در برنامههای معمولی خیلی بهش نمیپردازیم. اما به طور کلی، Node.js این مرحله رو برای آمادهسازی خودش انجام میده تا وارد مراحل بعدی بشه.
۴. Poll (پُل)
مرحلهی پُل، قلب تپندهی Event Loop هست. اینجا، Node.js منتظره که ببینه آیا اتفاقی میافته یا نه. یعنی در اینجا منتظره تا رویدادی بیفته، مثل دریافت یک درخواست جدید، اتصال جدید، یا هر چیز دیگهای که به صورت غیرهمزمان نیاز به پردازش داشته باشه.
اگر رویدادی نباشه، ممکنه یه مدت وایسه یا حتی به فازهای بعدی بره. این مرحله بهطور کلی مسئول نظارت بر وقوع رویدادهای جدید هست.
مثال: فرض کن یک کاربر یه درخواست ارسال کرده و حالا Node.js منتظره که جواب از دیتابیس بیاد. تا وقتی که جواب نیاد، هیچکاری نمیکنه و منتظر میمونه.
۵. Check (چک)
بعد از مرحلهی پُل، نوبت به توابعی میرسه که با setImmediate() تنظیم شدهاند. این توابع بعد از مرحلهی پُل و قبل از مرحلهی Close Callbacks اجرا میشن.
این مرحله به نوعی نظارت میکنه که اگه هنوز چیزی منتظره نباشه، توابعی که باید فوراً بعد از پُل اجرا بشن، اجرا بشن.
۶. Close Callbacks (کالبکهای بستهشدن)
مرحلهی آخر، مرحلهی کالبکهای بستهشدن هست. اینجا، توابعی که نیاز به اجرا شدن بعد از بسته شدن چیزی دارن، اجرا میشن. مثلاً وقتی یک سوکت بسته میشه و باید کالبک اجرا بشه، اینجا انجام میشه.
مثال: فرض کن یک اتصال شبکه بسته میشه و باید یه فعالیت خاصی مثل بستن فایلها یا آزادسازی منابع انجام بشه. این مرحله هم همون کار رو میکنه.
نتیجهگیری :
حالا که این مراحل رو با هم مرور کردیم، متوجه شدیم که چطور Node.js از این فازها برای مدیریت کارهای غیر همزمان استفاده میکنه. این فرآیند پیچیده، ولی در عین حال خیلی کارآمد هست و باعث میشه که Node.js بتونه به طور همزمان تعداد زیادی از کارها رو انجام بده بدون اینکه نیاز به چندین نخ (thread) داشته باشه.
اینکه بدونید Event Loop چطور کار میکنه، بهتون کمک میکنه که درک بهتری از نحوه عملکرد Node.js داشته باشید و بتونید برنامههاتون رو بهینهتر بنویسید.
@erfuuan_dev
🙏2
Forwarded from تهلاگ / Tehlug
ثبتنام رویداد ۲۷۷ تهلاگ آغاز شد! 🎉
رویداد ۲۷۷ در روز پنجشنبه، ۱۱ بهمن ۱۴۰۳ شامل ۶ ارائه فنی و ۲ کارگاه آموزشی برگزار میشود و فرصتی عالی برای علاقهمندان به لینوکس، جامعه نرمافزار آزاد و متنباز، پایتون و فناوریهای کلود است.
اطلاعات بیشتر و ثبتنام :
🔗 evand.com/events/tehlug277
@TehranLUG
رویداد ۲۷۷ در روز پنجشنبه، ۱۱ بهمن ۱۴۰۳ شامل ۶ ارائه فنی و ۲ کارگاه آموزشی برگزار میشود و فرصتی عالی برای علاقهمندان به لینوکس، جامعه نرمافزار آزاد و متنباز، پایتون و فناوریهای کلود است.
اطلاعات بیشتر و ثبتنام :
🔗 evand.com/events/tehlug277
@TehranLUG
❤1
به تازگی شروع کردم یادگرفتن Go . نکاتی که حس میکنم بدرد میخوره اینجا هم میزارم
امروز داشتم درباره سیستم های Rules Engine مطالعه میکردم. یکم دیگه درباره شون مینویسم
👍2
داشتم دربارهی Rule Engine یا همون موتور قوانین میخوندم، دیدم چقدر چیز باحالیه واسه وقتی که قراره کلی شرط و منطق رو توی یه برنامه پیاده کنیم، مخصوصاً جاهایی مثل اپ بانکی.
مثلاً فرض کن یه قانون داریم که اگه حقوق طرف بالای ۷۰ تومن باشه و امتیاز اعتباریش بالای ۹۰۰، اون وقت میتونیم ۶۰ درصد وام درخواستیشو براش تصویب کنیم. خب اینجور قوانین اگه یکیدوتا باشه با کدنویسی ساده میسازیش، ولی وقتی تعداد قوانین زیاد میشه یا هی تغییر میکنن، دیگه کنترلش از دست در میره. تازه اگه بخوای کسایی که برنامهنویس نیستن هم بتونن قانونا رو بفهمن یا عوض کنن، باید یه راه سادهتر پیدا کرد.
اینجاست که Rule Engine وارد میشه. توی این سیستم، قوانین به صورت «اگر فلان شد، پس بهمان کن» تعریف میشن. بهش میگی مثلاً اگه حقوق بالای ۷۰ بود و امتیاز بالای ۹۰۰، اون وقت وام رو تایید کن. این قوانین توی یه جایی ذخیره میشن (مثلاً یه فایل یا دیتابیس)، بعد یه چیزی به اسم Inference Engine یا موتور استنتاج میاد این قوانین رو با دادهها بررسی میکنه، اگه شرطی درست بود، اکشنش رو اجرا میکنه.
یه قسمت جالب دیگهش اینه که دو تا روش داره برای اینکه تصمیم بگیره:
۱. رو به جلو (Forward Chaining) یعنی از دادهها شروع میکنه تا ببینه به چه نتیجهای میرسه.
۲. رو به عقب (Backward Chaining) یعنی اول هدفو میذاره جلوش، بعد میگرده ببینه برای رسیدن به اون هدف باید چه شرایطی درست باشه.
خلاصهاش اینکه Rule Engine باعث میشه منطق کسبوکار رو جدا از خود برنامه نگه داریم، راحتتر مدیریت کنیم، نیاز به تغییر کد نداشته باشیم، و حتی بیزینسیها هم بتونن باهاش کار کنن. کلی هم باعث تمیزتر شدن کد و بهتر شدن کارایی میشه.
مثلاً فرض کن یه قانون داریم که اگه حقوق طرف بالای ۷۰ تومن باشه و امتیاز اعتباریش بالای ۹۰۰، اون وقت میتونیم ۶۰ درصد وام درخواستیشو براش تصویب کنیم. خب اینجور قوانین اگه یکیدوتا باشه با کدنویسی ساده میسازیش، ولی وقتی تعداد قوانین زیاد میشه یا هی تغییر میکنن، دیگه کنترلش از دست در میره. تازه اگه بخوای کسایی که برنامهنویس نیستن هم بتونن قانونا رو بفهمن یا عوض کنن، باید یه راه سادهتر پیدا کرد.
اینجاست که Rule Engine وارد میشه. توی این سیستم، قوانین به صورت «اگر فلان شد، پس بهمان کن» تعریف میشن. بهش میگی مثلاً اگه حقوق بالای ۷۰ بود و امتیاز بالای ۹۰۰، اون وقت وام رو تایید کن. این قوانین توی یه جایی ذخیره میشن (مثلاً یه فایل یا دیتابیس)، بعد یه چیزی به اسم Inference Engine یا موتور استنتاج میاد این قوانین رو با دادهها بررسی میکنه، اگه شرطی درست بود، اکشنش رو اجرا میکنه.
یه قسمت جالب دیگهش اینه که دو تا روش داره برای اینکه تصمیم بگیره:
۱. رو به جلو (Forward Chaining) یعنی از دادهها شروع میکنه تا ببینه به چه نتیجهای میرسه.
۲. رو به عقب (Backward Chaining) یعنی اول هدفو میذاره جلوش، بعد میگرده ببینه برای رسیدن به اون هدف باید چه شرایطی درست باشه.
خلاصهاش اینکه Rule Engine باعث میشه منطق کسبوکار رو جدا از خود برنامه نگه داریم، راحتتر مدیریت کنیم، نیاز به تغییر کد نداشته باشیم، و حتی بیزینسیها هم بتونن باهاش کار کنن. کلی هم باعث تمیزتر شدن کد و بهتر شدن کارایی میشه.
به نظرم یکی از چیزایی که یه برنامهنویس یا مهندس نرم افزار باید بلد باشه، وصل کردن سیستمهای مختلف به همه. مثلاً با Rule Engine میتونی کلی سناریو بسازی و وقتی به سیستمای دیگه وصلش کنی، یه چرخه کامل و خودکار درمیاد.
👍1
⏱️ حملهی زمانی (Timing Attack) تو Node.js چیه و چطوری جلوش رو بگیریم؟
Timing Attack یعنی هکر فقط با اندازهگیری زمان پاسخ سرور، میتونه حدس بزنه چه بخشهایی از یه رمز یا توکن درسته!
مثلاً وقتی مقایسهی رمز از چپ به راست انجام میشه، سرور همونجا که mismatch پیدا کنه، متوقف میشه. این باعث میشه زمان پاسخ متغیر باشه و از همین زمان، اطلاعات لو بره.
مثال:
مقایسهی بالا variable-time هست و میتونه اطلاعات رمز رو لو بده.
راهحلها 🔐
✅ ۱. استفاده از timingSafeEqual
مقایسهی ثابت زمان، فرق نمیکنه رشته چقدر شباهت داشته باشه.
🧂 ۲. استفاده از هشهای کند مثل bcrypt یا scrypt
با این کار، brute-force کردن رمز زمانبر میشه.
🔄 ۳. اجتناب از شرطهای مبتنی بر اطلاعات حساس
این مدل شرطها هم لو میدن که رمز از کجا شروع شده.
🕒 ۴. تاخیر ثابت بذار برای همهی پاسخها
Timing Attack یعنی هکر فقط با اندازهگیری زمان پاسخ سرور، میتونه حدس بزنه چه بخشهایی از یه رمز یا توکن درسته!
مثلاً وقتی مقایسهی رمز از چپ به راست انجام میشه، سرور همونجا که mismatch پیدا کنه، متوقف میشه. این باعث میشه زمان پاسخ متغیر باشه و از همین زمان، اطلاعات لو بره.
مثال:
if (input === secretToken) {
// ...
}مقایسهی بالا variable-time هست و میتونه اطلاعات رمز رو لو بده.
راهحلها 🔐
✅ ۱. استفاده از timingSafeEqual
import { timingSafeEqual } from 'node:crypto';
const a = Buffer.from(userInput, 'utf8');
const b = Buffer.from(secret, 'utf8');
if (a.length === b.length && timingSafeEqual(a, b)) {
// امنه
}مقایسهی ثابت زمان، فرق نمیکنه رشته چقدر شباهت داشته باشه.
🧂 ۲. استفاده از هشهای کند مثل bcrypt یا scrypt
با این کار، brute-force کردن رمز زمانبر میشه.
🔄 ۳. اجتناب از شرطهای مبتنی بر اطلاعات حساس
if (password.startsWith('admin')) {
// خطرناک!
}این مدل شرطها هم لو میدن که رمز از کجا شروع شده.
🕒 ۴. تاخیر ثابت بذار برای همهی پاسخها
const delay = 200; // ms
const elapsed = Date.now() - start;
await new Promise(r => setTimeout(r, Math.max(0, delay - elapsed)));