מה Node בעצם
Node.js היא תוכנה שמתקינים במחשב ושמריצה קובצי JavaScript. זה התיאור הפשוט ביותר, והוא מדויק. כשמקלידים node script.js, Node קורא את הקובץ, מעביר אותו למנוע V8 של Google (מנוע ה-JavaScript של Chrome) ומריץ אותו, עם ספרייה גדולה של APIs נוספים שמחוברים אליו בשביל דברים ש-V8 לא יודע לעשות לבד.
V8 יודע להריץ JavaScript. הוא לא יודע לפתוח קובץ, להאזין ל-TCP socket, להפעיל תהליך או לקרוא משתנה סביבה. Node מספק את כל זה, כתוב ב-C++, וחושף אותו לקוד ה-JavaScript שלכם כמודולים מובנים.
node --version
node script.js
אז Node הוא לא שפה. הוא גם לא framework. הוא runtime, סביבת ריצה: V8 ועוד ספרייה סטנדרטית ועוד מערכת מודולים ועוד event loop. זה כל הסיפור.
סקריפט ראשון
כל קובץ .js הוא תוכנית Node תקינה. בלי קוד שלד, בלי פונקציית main:
console.log עובד בדיוק כמו בדפדפן. Template literals, Date, מערכים, promises: כל יכולות השפה שאתם כבר מכירים מגיעות מ-V8 ומתנהגות באותה צורה. מה שמשתנה ב-Node הוא מה שזמין מסביב לשפה.
Globals שקיימים רק ב-Node
לדפדפן יש window, document, localStorage, fetch. ל-Node יש סט אחר של globals, שמותאם לסביבת ריצה בצד השרת:
processהוא תהליך ה-Node שרץ כרגע. הוא מחזיק את משתני הסביבה (process.env), את הארגומנטים משורת הפקודה (process.argv), ומתודות ליציאה (process.exit(1)).__filenameו-__dirnameנותנים את הנתיב המוחלט של הקובץ הנוכחי ושל התיקייה שלו. (במודולי ES הם לא קיימים, ומשתמשים במקומם ב-import.meta.url.)globalהוא האובייקט העליון, המקבילה שלwindowב-Node.
אין document ואין window. אם מנסים להשתמש בהם מקבלים ReferenceError. זה בדרך כלל הרמז הראשון לכך שספרייה נכתבה לדפדפן ולא תרוץ ב-Node כמו שהיא.
ארגומנטים משורת הפקודה ומשתני סביבה
חלק גדול ממה שעושים עם Node, כלי CLI, סקריפטים של build ושרתים, צריך לקרוא ארגומנטים ומשתני סביבה. שניהם נמצאים על process:
process.argv הוא מערך: שני הפריטים הראשונים הם הנתיב לקובץ ההרצה של Node והנתיב לסקריפט, כך שהארגומנטים האמיתיים מתחילים באינדקס 2. process.env הוא אובייקט רגיל של משתני סביבה, וקריאה של NODE_ENV, PORT או מפתחות API ממנו היא פרקטיקה מקובלת.
מודולים מובנים
Node מגיע עם ספרייה סטנדרטית שניגשים אליה דרך require (CommonJS) או import (ESM). שמות המודולים מתחילים ב-node: כדי שיהיה ברור שהם מובנים:
אלה שתשתמשו בהם הכי הרבה:
node:fs: קריאה וכתיבה של קבצים. השתמשו ב-node:fs/promisesבשביל הגרסה עם async/await.node:path: חיבור, פענוח וניתוח של נתיבי קבצים בצורה שעובדת בכל מערכת הפעלה.node:http/node:https: בניית שרתי HTTP ושליחת בקשות.node:url: ניתוח ובנייה של כתובות URL.node:os: מידע על המחשב המארח.node:crypto: hashing, בתים אקראיים, הצפנה.
לא מתקינים את אלה. הם מגיעים עם Node. כל השאר מגיע מ-npm.
ה-event loop בקצרה
Node מריץ את ה-JavaScript שלכם על thread אחד, אבל מטפל בהרבה דברים במקביל. הטריק הוא ה-event loop. כשקוראים למשהו אסינכרוני, כמו קריאת קובץ, בקשת HTTP או טיימר, Node מעביר את העבודה עצמה למערכת ההפעלה (או ל-thread pool שלו) וממשיך לרוץ. כשהעבודה מסתיימת, callback נכנס לתור, והלולאה מריצה אותו כשהקוד הנוכחי מסיים.
הסדר שמודפס הוא 1, 4, 2, 3. קוד סינכרוני רץ קודם. אחריו microtasks (promises שהסתיימו). אחריהם טיימרים. זו הסיבה שלולאה איטית שעמוסה בחישובים חוסמת את כל השרת: יש רק thread אחד בשביל הקוד שלכם. המקביליות של Node נוגעת ל-I/O, לא לחישוב.
שרת HTTP קטנטן
התמורה של כל זה היא ששרת web עובד נכנס בכמה שורות:
בלי framework, בלי תלויות. createServer מקבלת פונקציה שרצה על כל בקשה, ו-listen מפעילה את ה-event loop כדי לטפל בחיבורים נכנסים. אפליקציות אמיתיות משתמשות ב-Express או ב-Fastify מעל זה, אבל מתחת לפני השטח זה אותו מודול http מובנה.
Node מול הדפדפן
כדאי להגיד במפורש מה עובר ומה לא:
| עובד בשניהם | רק ב-Node | רק בדפדפן |
|---|---|---|
יכולות השפה (classes, promises, async/await) | fs, http, process, __dirname | window, document, DOM |
console.log | require של CommonJS / מוזרויות ESM ייחודיות ל-Node | localStorage, sessionStorage |
fetch (Node 18+) | גישה למערכת הקבצים ול-sockets של רשת | אירועי משתמש, רינדור |
setTimeout, setInterval | תהליכי בן, streams | History API, navigator |
Node המודרני אימץ כמה APIs של דפדפן, כמו fetch, URL, AbortController ו-structuredClone, כך שהפער קטן יותר ממה שהיה. אבל ה-DOM לא מגיע ל-Node, ומערכת הקבצים לא מגיעה לדפדפן.
Node מול Deno מול Bun
Node הוא ברירת המחדל, אבל הוא כבר לא סביבת הריצה היחידה ל-JavaScript. Deno ו-Bun הן חלופות: Deno מהיוצר המקורי של Node, ו-Bun מצוות חדש יותר שמתמקד במהירות. הן מריצות JavaScript (ו-TypeScript, באופן מובנה), מגיעות עם כלים מובנים כמו test runners ו-bundlers, ושונות מ-Node באופן שבו הן מטפלות במודולים, בהרשאות ובהתקנת חבילות.
ללימוד JavaScript, Node הוא עדיין המקום שבו נמצאים התיעוד, המדריכים ומשרות העבודה. המושגים, event loop, מודולים ו-APIs מובנים, עוברים כמעט במלואם לסביבות הריצה האחרות. למדו קודם Node, ותכירו את האחרות כשפרויקט ידרוש אותן.
להריץ סקריפטים, מהר
כמה דרכים להריץ קוד בפועל תוך כדי עבודה:
# Run a file
node script.js
# Run a one-liner
node -e "console.log(2 ** 10)"
# Open the REPL (interactive prompt)
node
# Watch a file and re-run on save (Node 18.11+)
node --watch script.js
ה-REPL הוא דף טיוטה נוח כשרוצים לבדוק מה מתודה מחזירה בלי ליצור קובץ. --watch שימושי בזמן פיתוח: שומרים, ו-Node מריץ מחדש את הסקריפט אוטומטית.
הבא בתור: תפיסת שגיאות
להריץ קוד זה דבר אחד, ולטפל בו כשמשהו משתבש זה דבר אחר. קריאות קבצים נכשלות, בקשות HTTP נתקעות, פענוח JSON זורק שגיאות. הפרק הבא עוסק ב-try/catch, בסוגי שגיאות ובדפוסים להתמודדות עם דברים שנשברים, וזה, בתוכנית Node, קורה בסוף לכל דבר.
שאלות נפוצות
מה זה Node.js runtime?
Node.js היא תוכנה שמריצה JavaScript מחוץ לדפדפן. היא משלבת את מנוע V8 של Google (אותו מנוע שמריץ JS ב-Chrome) עם שכבת C++ שמספקת APIs שאין ל-V8 בעצמו: גישה למערכת הקבצים, רשת, תהליכים וטיימרים. השילוב הזה הוא מה שמאפשר לבנות שרתים, כלי CLI וכלי build ב-JavaScript.
במה Node שונה מהדפדפן?
שניהם מריצים JavaScript, אבל ה-APIs שמסביב לשפה שונים. הדפדפן נותן לכם window, document ואת ה-DOM. Node נותן לכם process, fs, http, __dirname וטעינת מודולים ב-CommonJS/ESM. אין DOM ב-Node ואין מערכת קבצים בדפדפן: השפה משותפת, הפלטפורמה לא.
האם Node.js הוא framework או runtime?
runtime. Node עצמו לא כופה שום מבנה על האפליקציה: הוא רק מריץ JavaScript וחושף APIs. Frameworks כמו Express, Next.js או NestJS בנויים מעל Node. Deno ו-Bun הן סביבות ריצה חלופיות ל-JavaScript שמתחרות ב-Node אבל ממלאות את אותו תפקיד.
מה זה ה-event loop ב-Node?
ה-event loop הוא מה שמאפשר ל-Node לטפל בהרבה דברים במקביל על thread אחד. כשקוראים למשהו אסינכרוני, כמו קריאת קובץ, בקשת HTTP או setTimeout, Node מעביר את העבודה למערכת וממשיך לרוץ. כשהעבודה מסתיימת, ה-callback שלה נכנס לתור וה-event loop מריץ אותו. בגלל זה fs.readFile לא חוסם את שאר התוכנית.