Node.js: הסבר מלא על הטכנולוגיה ואופן הפעולה שלה

Logo of Node.js

לפני שנתחיל ללמוד על Node.js, נשאל שאלה. מה חלק מ-JavaScript?

נענה על השאלה בהמשך המאמר.

מה זה Node.js?

Node.js היא סביבת הרצה של JavaScript שנבנתה על גבי מנוע JavaScript V8 של Google, ומשומשת בעיקר להריץ קוד Javascript בצד שרת. Node.js היא event-driven(single thread), non-blocking I/O model, הכוונה שיש לה רק thread אחד כדי לבצע את המשימות, אבל היא יכולה למלא אחר מספר בקשות במקביל כי היא לא חוסמת (non-blocking) את ההרצה של התוכנה כשיש פעולות אסינכרוניות.

בואו נכנס קצת יותר עמוק ונפרק את הפסקה הזו לחלקים:

Node.js היא סביבת הרצה של JavaScript שנבנתה על גבי מנוע V8 JavaScript engine של Google.

סביבת הרצה - Runtime environment

הכוונה בסביבת הרצה היא המקום שבו אנחנו מריצים קוד מסוים. כל סביבת הרצה היא שונה ותספק לנו פונקציות ויכולות מיוחדות בהתאם לסביבה בה אנחנו כותבים את הקוד. לדוגמה, Chrome היא גם סביבת הרצה כמו Node.js, שנבנתה על גבי V8 ומאפשרת לנו להריץ קוד ולגשת ל-DOM API's, או לבצע button click events. אבל ב-Node.js אין תמיכה טבעית (built-in) ב-DOM API's לדוגמה, אבל איך זה אם שניהם בנויים על אותה טכנולוגיה (V8 JavaScript engine)?

V8 JavaScript engine

המנוע V8 JavaScript engine נכתב בשפת ++C ותפקידו הוא לקחת קוד של JavaScript ולהמיר אותו לקוד מכונה, וכך המחשב שלכם יכול להריץ את אותו קוד. גם Node.js וגם Chrome נבנו על גבי V8, זה אומר ששניהם נבנו ברובם על ידי ++C וזה אומר שבאמצעות ++C בשילוב עם V8, יצרנו שתי סביבות הרצה שמספקות פונקציות ויכולות שונות בהתאם לסביבה. אבל זה אומר עוד משהו מיוחד, זה אומר שלכל מי שיש ידע ב-++C יכול לחבר את ה-V8 JavaScript engine לאפליקציה וליצור בעצמו סביבת הרצה ולהרחיב בעצמו את היכולות של Javascript!

קצת מסובך? בואו נראה דוגמה:
Andrew Mead, Rob Percival

בתמונה תוכלו לראות את שתי סביבות ההרצה שדיברנו עליהן (Node.js & Chrome) ואיך V8 JavaScript engine לוקח קוד JavaScript, וממיר אותו ל-machine code כך שהמחשב שלכם יוכל לבצע. שימו לב כי פונקציות שחשבתם שהם של Javascript הם בעצם Implementation של ++C, וכדי שנוכל לגשת אליהן, סביבת ההרצה מספק לנו את שכבה כמו Intermediate language שמאפשרת לנו לגשת אל אותן API's.

אם כך, נחזור לשאלה שלנו, מה חלק מ-JavaScript?

  • DOM
  • LocalStorage
  • setTimeout
  • console.log

התשובה כבר לא צריכה להפתיע אתכם, אבל אף אחד מהאפשרויות לא באמת חלק מ-JavaScript, זה רק ה-Implementation של סביבת ההרצה V8 JavaScript engine שנכתבה על ידי ++C שנותנת לנו לגשת ולבצע את הפעולות האלו של ה-API's דרך JavaScript.

איך Node.js עובד?

עכשיו הגענו לחלק השני של הפסקה שהוא: Node.js היא event-driven(single thread), non-blocking I/O model. כדי להקל על ההסבר, גם את המשפט הזה נחלק לשלושה חלקים:

קלט/פלט - I/O Model (input/output)

I/O, או במלואו Input/Output (קלט/פלט), הוא תהליך התקשורת של המחשב עם מערכות אחרות. לדוגמה, קריאת קובץ מהדיסק הקשיח, שליחת נתונים דרך הרשת וגם פעולות אסינכרוניות, כמו לשאוב מידע מ-APIs, הן דוגמא לפעולות I/O.

Non-blocking

במודל non-blocking, פעולות אסינכרוניות כמו שאיבת מידע מ-APIs יכולות לקחת זמן (נניח, 5 שניות). במהלך זמן הבקשה, אנחנו רוצים שהתוכנה שלנו תמשיך לעבוד ולא תיתקע. אם Node.js לא היה מיישם יכולת non-blocking, המחשב שלנו היה 'קופא' ולא יכול היה לבצע פעולות אחרות עד לסיום אותה בקשה. לכן, מודל ה-non-blocking אומר שאנחנו יכולים לבצע פעולות אסינכרוניות מבלי לחשוש שהתוכנה שלנו תיתקע, וכך Node.js מאפשר לנו לטפל בבקשות האלו בצורה יעילה ומיטבית.

Event-driven (single thread)

זה התהליך ש-Node.js עושה כדי לרשום את אותן קריאות (callbacks) ולקרוא להם מתי שה-API's מסיימים ומחזירים תשובה (Response). ואת התהליך הזה ניתן לחלק לארבע שלבים:

  1. Call Stack

    תפקידו הוא לעקוב אחר הפונקציות המבוצעות כרגע בתוכנה, אלו הפונקציות שהם לא אסינכרוניים.

  2. Node APIs

    כשיש לנו פעולה אסינכרונית, אנחנו רושמים אותה כאל event בתוך Node API's והיא ממשיכה להתבצע ברקע, כלומר אנחנו לא מחכים לתוצאה (Response), אלא אנחנו ממשיכים הלאה בקוד שלנו כדי לטפל בעוד בקשות ובכלל להמשיך להיות זמינים גם לפעולות אחרות.

  3. Callback Queue

    כשהפעולה מסתיימת, אנחנו מעבירים את הקריאה שלנו ל-Callback Queue ומחכים שה-EventLoop יקרא לה.

  4. EventLoop

    תפקידו של EventLoop הוא להסתכל על שני דברים: (Call Stack & Callback Queue). כלומר, אם ה-Call Stack ריק, ה-EventLoop יתחיל להריץ את הפונקציות שיש בתוך ה-Callback Queue. אבל אם ה-Call Stack לא ריק, אנחנו נמשיך לחכות ולא נבצע את הפונקציות שחיכו בתוך ה-Callback Queue. כלומר ה-EventLoop צריך לחכות עד שה-Call Stack יהיה פנוי, ורק לאחר מכן נוכל לבצע את הקריאות שחיכו ב-Callback Queue.

Single Thread

single thread אומר שיש thread (חייל) אחד שמטפל במגוון משימות, כמו לנהל בקשות HTTP, להריץ פונקציות JavaScript ועוד. זה שונה מ-multiple threads שזה אומר שיש הרבה חיילים שיכולים לבצע את המשימות האלו במקביל.

ל-Node.js יש חייל אחד שמטפל בכל המשימות האלו וזה נשמע כאילו זה יכול להיות חיסרון, אבל במציאות, זה יתרון גדול. מכיוון שהוא עובד לבד, הוא יודע לעבוד בצורה יעילה מאוד, לחסוך במשאבי זיכרון ומעבד ומפחית את הצורך בתיאום עם threads (חיילים) אחרים. זה גם עוזר לנו לכתוב קוד פשוט יותר מכיוון שאין צורך להתמודד עם בעיות כמו תחרות על משאבים שמתרחשים ביישומים שהם multiple threads.

למה כדי לנו להשתמש ב-Node.js?

ל-Node.js יש יותר מכמה סיבות למה להשתמש בו, אנחנו נחקור את הבולטות ביותר:

  • סקלוביליות גבוהה (Highly scalable)

    ל-Node.js יש את היכולות להתמודד עם כמה משימות במקביל ולא להיתקע (non-blocking), מה שאומר שבעזרת Node.js אנחנו יכולים לטפל ביותר לקוחות ולתת תשומת לב לכולם. העובדה הזו, ביחד עם event-driven מאפשרים ל-Node.js להיות גמיש ומותאם ליישומים עם עומסי עבודה גבוהים של I/O, כמו שרתי API, מערכות streaming, ויישומים שמבצעים המון בקשות אסינכרוניות.

  • עומסי נתונים (Data-intensive)

    ל-Node.js יש את היכולות לנהל ולהתמודד עם כמות מידע (תהליכים גדולים וארוכים) בצורה יעילה שלא תוקעת את המערכת (thread) רק על אותה משימה ספציפית, אלא בזמן שהבקשה מעובדת, Node.js זמין לקבל בקשות נוספות, מה שאומר שה-thread זמין. כאשר התגובה מהמשימה המקורית מגיעה, היא מועברת ל-Callback Queue. זה מאפשר ניצול מקסימלי של המערכת.

  • יישומים בזמן אמת (Real-time applications)

    Node.js מותאם במיוחד ליישומים בזמן אמת (כמו WhatsApp), שבהם נדרשים שינויים מיידים ותגובות מהירות. בפועל, Node.js מאפשר תקשורת דו-כיוונית ומסוגל להשתלב עם WebSockets, מה שמקל על יצירת תקשורת בזמן אמת.

  • JavaScript ל-Backend ו-Frontend

    השימוש ב-Node.js מאפשר למתכנתים להשתמש ב-JavaScript גם בצד השרת וגם בצד הלקוח, מה שמאפשר למתכנתים לתכנת Full Stack Web Applications בשפה אחת!

  • פופולריות וקהילה תומכת

    Node.js נהנית מפופולריות גבוהה וקהילה גדולה של מפתחים, מה שמאפשר גישה רחבה למשאבים, ספריות ותמיכה מכל העולם! בנוסף מלא חברות גדולות כמו PayPal מספרות עד כמה Node.js עזרו להם:

    • שיפור ביצועי היישום: בזכות Node.js הצליחה PayPal לטפל בבקשות פי 2x לעומת הגרסה ב-Java.
    • הפחתת זמן התגובה: המעבר ל-Node.js הוביל להפחתה של 35% בזמן התגובה הממוצע, מה שהביא לחוויית משתמש מהירה יותר.
    • הפחתת מספר שורות קוד: במהלך המעבר ל-Node.js, יישמה PayPal את אותו פונקציונליות שהייתה להם ב-Java, אך עם 33% פחות שורות קוד. זו הפחתה משמעותית בכמות הקוד הדרושה, המעידה על יעילות גבוהה והקלות בפיתוח ובתחזוקה.

אבל לא רק PayPal, נכון לשנת 2024, מספר חברות מובילות משתמשות ב-Node.js בבאקנד שלהן, והנה כמה דוגמאות:

חברות שמשתמשות ב-Node.js בבאקנד שלהן, לשנת 2024:

  • Uber משתמשת ב-Node.js לטיפול במספר עצום של נתונים ובקשות משתמש בזמן אמת, מה שמאפשר לה לשמור על מהירות ויעילות בפלטפורמה הגדולה והמורכבת שלה.
  • NASA עברה ל-Node.js ושיפרה באופן משמעותי את זמני הגישה לנתונים ואת ניהול הנתונים בענן, מדגימה את יכולת של Node.js לטפל ביישומים קריטיים ובקנה מידה גדול.
  • LinkedIn & Trello שילבו את Node.js כדי להשיג יכולת עיבוד נתונים מהירה וביצועים גבוהים במערכות המבוססות על נתונים ומשימות בזמן אמת, שיפרו את זמינות השירות.
  • Netflix במקור השתמשה ב-Java בבאקנד שלה, החברה עברה ל-Node.js ושיפרה באופן משמעותי את זמן הטעינה של האפליקציה, קיצצה את זמן הטעינה ב-70%, ושיפרה את חוויית המשתמש.