כיצד פועל לולאת האירועים ב- JavaScript?

למרות שזה עשוי לדרוש הבנה מעמיקה של שפות כמו C ++ ו- C כדי לכתוב קוד ייצור בקנה מידה מלא, לרוב ניתן לכתוב JavaScript מתוך הבנה בסיסית בלבד מה ניתן לעשות עם השפה..


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

כמפתח JavaScript, יותר ויותר חשוב להבין מה באמת קורה מתחת למכסה המנוע ואיך רוב המורכבויות הללו המופשטות מאיתנו באמת עובדות. זה עוזר לנו לקבל החלטות מושכלות יותר, שיכולות, בתורו, להגביר את ביצועי הקוד בצורה דרסטית.

מאמר זה מתמקד באחד המושגים או המונחים החשובים מאוד אך לעיתים רחוקות. ה לולאת אירועים!. 

אי אפשר להימנע מכתיבת קוד אסינכרוני ב- JavaScript, אך מדוע משמעות קוד שפועל באופן אסינכרוני? כלומר. לולאת האירועים

לפני שנוכל להבין כיצד לולאת האירועים עובדת עלינו להבין קודם מה זה JavaScript עצמו ואיך הוא עובד!

מה זה JavaScript?

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

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

רגע, מה זה? הגדרה ספרית? ��

בואו נשבר את זה!

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

חוט יחיד

חוט ביצוע הוא הרצף הקטן ביותר של הוראות מתוכנתות שניתן לנהל באופן עצמאי על ידי מתזמן. שפת תכנות היא חד-הברגה פירושה שהיא יכולה לבצע משימה או פעולה אחת בלבד בפעם אחת. המשמעות היא שהיא תבצע תהליך שלם מתחילתו ועד סופו מבלי שהחוט יופרע או יופסק.

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

איך JavaScript יכול להיות חד-הברגה ו לא חוסם באותו הזמן?

אבל מה פירוש החסימה?

לא חוסם

אין הגדרה אחת לחסימה; זה פשוט אומר דברים שרצים לאט על החוט. אז אי-חסימה פירושה דברים שאינם איטיים בחוט.

אבל רגע, האם אמרתי שג’אווה סקריפט פועל על חוט בודד? ואני גם אמרתי את זה לא חוסם, מה שאומר שהמשימה רצה במהירות בערימת השיחות? אבל איך??? מה דעתך כשאנחנו מנהלים טיימרים? לולאות?

תירגעו! נגלה קצת ��.

במקביל

משמעות מקדמה היא שהקוד מבוצע במקביל על ידי יותר מאשכול אחד.

אוקיי, הדברים מתחילים להיות ממש מוזר עכשיו, איך JavaScript יכול להיות חד-הברגה ולהיות בו-זמנית? כלומר, ביצוע קודו ביותר מ- thread אחד?

אסינכרוני

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

אבל ל- JavaScript יש חוט בודד? מה לאחר מכן מבצע את קוד החסימה הזה תוך מתן ביצוע של קודים אחרים בשרשור?

לפני שנמשיך, נקבל סקירה כללית של האמור לעיל.

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

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

בואו נעבור קצת יותר לעומק, בואו נעבור למנועי זמן ההפעלה של JavaScript, V8, אולי יש בו כמה חוטים מוסתרים שלא ידוע לנו עליהם.

מנוע V8

מנוע ה- V8 הוא מנוע זמן ריצה של הרכבה אינטרנטית בעל קוד ביצועים גבוה עבור JavaScript שנכתב ב- C ++ על ידי Google. רוב הדפדפנים מפעילים JavaScript באמצעות מנוע V8, ואפילו סביבת זמן הריצה הפופולרית של הצומת js משתמשת בזה.

באנגלית פשוטה, V8 היא תוכנית C ++, שמקבלת קוד JavaScript, מהדר ומבצע אותו.

ה- V8 עושה שני דברים עיקריים;

  • הקצאת זיכרון ערימה
  • הקשר לביצוע ערימת שיחות

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

פתיל אחד === ערימת שיחה אחת === ביצוע אחד בכל פעם.

תמונה – האקר בצהריים

מכיוון של- V8 יש רק מחסנית שיחה אחת, כיצד JavaScript פועל במקביל ובלתי-סינכרוני מבלי לחסום את שרשור הביצוע הראשי?

ננסה לגלות זאת על ידי כתיבת קוד אסינכרוני פשוט ועם זאת נפוץ וננתח אותו יחד.

JavaScript מפעיל כל קוד שורה אחר שורה, בזה אחר זה (חד-הברגה). כצפוי, השורה הראשונה נדפסת בקונסולה כאן, אבל מדוע השורה האחרונה מודפסת לפני קוד הזמן הקצוב? מדוע תהליך הביצוע לא ממתין לקוד פסק הזמן (חסימת) לפני שהוא ממשיך להריץ את השורה האחרונה?

נראה כי חוט אחר עזר לנו לבצע פסק זמן זה מכיוון שאנחנו די בטוח שחוט יכול לבצע משימה אחת בלבד בכל נקודת זמן.

בוא ניקח הצצה אל תוך ה קוד המקור V8 לזמן מה.

רגע מה??!!! אין פונקציות טיימר ב- V8, אין DOM? אין אירועים? אין AJAX?…. הייססס!!!

אירועים, DOM, טיימרים וכו ‘אינם חלק מיישום הליבה של JavaScript, JavaScript תואם בקפדנות את מפרטי סקריפטים של אקמה, ולעיתים קרובות מתייחסים אליהם גרסאות שונות על פי מפרט סקריפטים של Ecma (ES X).

זרימת עבודה

אירועים, טיימרים, בקשות Ajax ניתנים בצד הלקוח על ידי הדפדפנים ולעיתים קרובות הם מכונים Web API. הם אלה המאפשרים ל- JavaScript החד-הברגה להיות חסימתי, במקביל ואסינכרוני! אבל איך?

ישנם שלושה חלקים עיקריים בזרימת העבודה של כל תוכנית JavaScript, ערימת השיחות, ממשק ה- API באינטרנט ותור המשימות.

ערימת השיחות

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

הבה נבחן את הדוגמא להלן;

מקור – https://youtu.be/8aGhZQkoFbQ

כשאתה מתקשר לפונקציה printSquare (), הוא נדחף אל ערימת השיחות, פונקציית printSquare () קוראת לפונקציה הריבועית (). פונקציית הריבוע () נדחפת אל הערימה וקוראת גם פונקציית הכפל (). פונקציית הכפלה נדחפת אל הערימה. מכיוון שפונקציית הכפל חוזרת והיא הדבר האחרון שנדחף לערימה, היא נפתרת תחילה והיא מוסרת מהערימה, אחריה הפונקציה ריבוע () ואז פונקצית printSquare ().

ממשק ה- API של האינטרנט

זה המקום בו קוד שאינו מטופל על ידי מנוע V8 מבוצע כדי לא “לחסום” את חוט הביצוע הראשי. כאשר ערימת השיחות נתקלת בפונקציה של ממשק API, התהליך מועבר מייד לממשק ה- API של האינטרנט, שם הוא מבוצע ומשחרר את מחסנית השיחה לבצע פעולות אחרות במהלך ביצועו..

נחזור לדוגמה setTimeout שלנו למעלה;

כשאנחנו מפעילים את הקוד, קו ה- console.log הראשון נדחף לערימה ואנחנו מקבלים את התפוקה שלנו כמעט מייד, כשמגיעים לפסק הזמן, טיימרים מטופלים על ידי הדפדפן ואינם חלק מיישום הליבה של V8, זה נדחף לממשק ה- API במקום זאת, לשחרר את הערימה כך שתוכל לבצע פעולות אחרות.

בעוד פסק הזמן עדיין פועל, הערימה עוברת לשורת הפעולה הבאה ומריצה את ה- console.log האחרון, מה שמסביר מדוע מוציאים את זה לפני פלט הטיימר. לאחר סיום הטיימר, קורה משהו. ה- console.log שנכנס ואז הטיימר מופיע באורח קסום בערימת השיחות!

איך?

לולאת האירועים

לפני שנדון בלולאת האירועים, בואו ונעבור ראשית את הפונקציה של תור המשימות.

בחזרה לדוגמא לפסק הזמן שלנו, ברגע שממשק ה- API של ה- Web מסיים לבצע את המשימה, הוא לא רק דוחף אותו חזרה אל ערימת השיחות באופן אוטומטי. זה עובר ל תור משימה. 

תור הוא מבנה נתונים שעובד על עיקרון ה- First in First out, כך שככל שמשימות נדחפות לתור, הן יוצאות באותו הסדר. משימות שבוצעו על ידי ממשקי ה- API של האינטרנט, שנדחפות לתור המשימות, ואז חוזרות אל ערימת השיחות כדי להדפיס את התוצאה שלהן.

אבל חכה. מה לעזאזל הוא לולאת האירועים???

מקור – https://youtu.be/8aGhZQkoFbQ

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

מקור – https://www.quora.com/How-does-an-event-loop-work/answer/Timothy-Maxwell

התרשים לעיל מדגים את זרימת העבודה הבסיסית בין לולאת האירועים לתור המשימות.

סיכום

למרות שמדובר במבוא בסיסי מאוד, הרעיון של תכנות אסינכרוני ב- JavaScript נותן תובנה מספקת בכדי להבין בבירור מה קורה מתחת למכסה המנוע ואיך JavaScript מסוגל לפעול במקביל ובאופן אסינכרוני רק עם חוט בודד..

JavaScript הוא תמיד לפי דרישה, ואם אתה סקרן ללמוד, הייתי ממליץ לך לבדוק זאת קורס אודמי.

Jeffrey Wilson Administrator
Sorry! The Author has not filled his profile.
follow me
    Like this post? Please share to your friends:
    Adblock
    detector
    map