আগের পাঠের সার্ভারটি একসাথে অনেক ব্রাউজার এতে আঘাত করলেও সামলাতে পারে, একটি রিকোয়েস্ট শেষ হওয়ার জন্য অপেক্ষা না করেই পরেরটি শুরু করে। এই পাঠটি ব্যাখ্যা করে কীভাবে — আর Node শুরুতেই কেন এভাবে ডিজাইন করা হয়েছিল।
অনেক সার্ভার প্ল্যাটফর্ম প্রতিটির জন্য একটি নতুন থ্রেড — এক্সিকিউশনের একটি আলাদা লাইন — শুরু করে concurrent রিকোয়েস্ট সামলায়। Node ঠিক উল্টোটা করে: আপনার JavaScript কোড একটি একক থ্রেডে চলে। যেকোনো মুহূর্তে আপনার কোডের শুধু একটি লাইন এক্সিকিউট হয়, কখনোই একাধিক নয়।
কৌশলটি হলো একটি সার্ভার সময়ের বেশিরভাগ যা করে তা আসলে গণনা নয় — এটি অপেক্ষা করা: ডিস্ক থেকে একটি ফাইল পড়া শেষ হওয়ার অপেক্ষা, একটি ডেটাবেসের সাড়া দেওয়ার অপেক্ষা, অন্য একটি সার্ভারের API-এর উত্তর দেওয়ার অপেক্ষা। Node সেই অপেক্ষাটি পেছনে অপারেটিং সিস্টেমকে হাতে দেয়, আর অপেক্ষা শেষ না হওয়া পর্যন্ত অলস বসে না থেকে সাথে সাথে পরের কোডের অংশে চলে যায়।
অপেক্ষা শেষ হলে — ফাইল পড়া হয়ে যায়, ডেটাবেস সাড়া দেয় — Node আপনার দেওয়া callback-টি সারিতে রাখে, আর একক থ্রেডটি ফাঁকা হওয়া মাত্র সেটি চালায়।
এই কারণেই আগের পাঠের সার্ভারটি প্রথম ভিজিটরের রিকোয়েস্ট এখনো হ্যান্ডেল হতে থাকা অবস্থায় দ্বিতীয় ভিজিটরকে সেবা দিতে পারে — যতক্ষণ হ্যান্ডলিংয়ে ভারী গণনার বদলে অপেক্ষা জড়িত থাকে (একটি ফাইল, একটি ডেটাবেস, একটি নেটওয়ার্ক কলের জন্য), সেই অপেক্ষার সময় একক থ্রেডটি অন্য রিকোয়েস্টে কাজ করতে মুক্ত থাকে।
যা এখনো থ্রেডকে ব্লক করতে পারে
উল্টো দিকটা হলো: সত্যিই ভারী গণনা — একটি বিশাল অ্যারে সর্ট করা, একটি জটিল হিসাব চালানো — চলার সময় সেই একক থ্রেডটিকে সম্পূর্ণভাবে ব্লক করে, আর বাকি প্রতিটি রিকোয়েস্টকে অপেক্ষা করতে হয়, কারণ চাপ নেওয়ার মতো দ্বিতীয় কোনো থ্রেড নেই। Node অনেক অপেক্ষারত অপারেশন একসাথে সামলাতে চমৎকার; CPU-ভারী কাজের জন্য এটি একটি খারাপ মিল।
আপনি খুব কমই সরাসরি "ইভেন্ট লুপ" কোড লেখেন — এটি স্বয়ংক্রিয়ভাবে চলে, আপনার লেখা প্রতিটি callback, promise, আর async/await-এর নিচে। কিন্তু এটি আছে তা বোঝা অনেক কিছু ব্যাখ্যা করে: কেন Node.js কোড এভাবে লেখা হয়, কেন সার্ভারে ব্লকিং ফাইল অপারেশন নিরুৎসাহিত করা হয়, আর কেন ইভেন্ট, callback, আর promise নিয়ে পরের বেশ কয়েকটি পাঠ যতটা গুরুত্বপূর্ণ মনে হয় ঠিক ততটাই গুরুত্বপূর্ণ।