PracticU

בעיית ה-Callback Hell

בלי כתוביותעם כתוביות
PracticU › קורס NodeJS › בעיית ה-Callback Hell
מילון מושגים:
Callback - פונקציה שמועברת כארגומנט לפונקציה אחרת כדי שתופעל מאוחר יותר, לרוב בסיום פעולה.
פונקציה - קטע קוד בעל שם שמבצע משימה מוגדרת, מקבל ערכי קלט (פרמטרים) ויכול להחזיר תוצאה. מאפשרת לארגן קוד ולהשתמש בו שוב.
שרת - מחשב או תוכנה שמספקים שירות למחשבים אחרים (לקוחות) ברשת, למשל אחסון קבצים, אתר אינטרנט או מסד נתונים, ומגיבים לבקשות שלהם.
Promise - אובייקט ב-JavaScript שמייצג תוצאה עתידית של פעולה אסינכרונית, שתושלם בהצלחה או תיכשל.
באג - תקלה או שגיאה בקוד שגורמת לתוכנה להתנהג בניגוד למצופה.

בעיית ה-Callback Hell
Callback Hell הוא מצב שבו פעולות אסינכרוניות מקוננות זו בתוך זו, וכל שלב תלוי בתוצאה של השלב הקודם. התוצאה היא קוד עם הזחה עמוקה שקשה לקרוא, לתחזק ולתקן.
דוגמה
בפונקציה getSite במודול longcalc מדמים גלישה לשרת מרוחק: מחכים שתי שניות ומחזירים מספר רנדומלי בין 0 ל-99. הפונקציה מחזירה Promise.
בקובץ הראשי קוראים לה ארבע פעמים ברצף. כל קריאה מקבלת את המספר מהקריאה הקודמת, ומעבירה אותו לקריאה הבאה בתוך then. התוצאה היא then בתוך then, והקוד הופך להזחה עמוקה.
מה הבעיה
הקוד עובד נכון מבחינה לוגית, וכל המספרים מודפסים בזמנם. אבל:
1. תחזוקה: קשה למצוא את המקום הנכון להוספת שלב חדש.
2. תיקון באגים: קשה לראות איפה השגיאה נמצאת בתוך ההזחה.
3. Promise לא פותר את זה לבד: המרצה הזהיר שאותה בעיה הייתה קיימת גם עם callbacks בלבד, ואם שורשרים פרומיסים בתוך פרומיסים.
הבעיה היא בצורת הכתיבה ולא בתוצאה, ולכן צריך דרך אחרת לכתוב את אותה לוגיקה.
השיעור הבא בקורס: הסבר של async ועל await

פרקי ההרצאה: בעיית ה-Callback Hell

  1. 00:00

    מהי בעיית Callback Hell

  2. 01:11

    פונקציה אסינכרונית שמדמה גלישה לשרת

  3. 02:22

    יצירת Promise עם Resolve ו-Reject

  4. 04:14

    קריאה לפונקציה והטיפול בתוצאה

  5. 05:50

    שרשור קריאות אסינכרוניות בתוך then

תמלול ההרצאה: בעיית ה-Callback Hell

הטקסט המלא של הדקות הראשונות בהרצאה «בעיית ה-Callback Hell» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.

  1. 00:02

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

  2. 00:17

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

  3. 00:34

    במצב כזה יש לנו פה קריאות מתוך פונקציות הסינכרוניות לתוך פונקציות הסינכרוניות, והמצב הזה נקרא callback hell. callback hell זה מצב שבו פונקציה קוראת לפונקציה שקוראת לפונקציה, אבל בצורה מאוד לא אלגנטית ומאוד לא יפה בקוד.

  4. 00:57

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

  5. 01:11

    בואו ניקח דוגמה שיש לנו איזושהי פונקציה במודול הנפרד long calculation שמבצעת גלישה לשרת מרוחק והפונקציה הזאת תקבל איזשהו url והיא תחזיר לנו בחזרה איזשהו נתון מסוים שאנחנו נגריל סתם איזשהו מספר רנדומלי אבל אנחנו רוצים להשתמש בו בשביל שוב פעם לקרוא ולשלוח לפונקציה אחרת או לאותה פונקציה עם url אחר

  6. 01:38

    בכדי להבין מה זה בדיוק המצב הזה של callback hell וכמובן גם איך לפתור אותו אם אנחנו משתמשים בטכניקה הרגילה של callbacks אין ממש אפשרות לפתור את הcallback hell נניח נשלח פה Error Callback ו-Success Callback.

  7. 02:03

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

  8. 02:14

    אז קודם כל, בואו רגע נחזיר return new promise. ה-promise כמובן אמרנו מקבל פונקציה אחת לסוגריים, הפונקציה האחת שהוא מקבל מקבלת resolve ו-reject, וכאן אנחנו בעצם רוצים לבצע את הקוד שכאילו גולש לשרת מרוחק.

  9. 02:36

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

  10. 02:51

    אז איך אנחנו מבצעים את הגלישה הזאת לשרת המרוחק? אז את הגלישה לשרת המרוחק אנחנו עושים על ידי הדמיה של set timeout, בואו נניח לוקח שלוש שניות.

  11. 03:07

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

  12. 03:19

    בואו ניקח כאן איזשהו number, ניקח math parse int וניתן לו את math.random כפול 100. בעצם הגרלנו כאן איזשהו מספר רנדומלי, אז אנחנו רוצים עכשיו בהצלחה לדווח אותו.

  13. 03:45

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

  14. 03:59

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

  15. 04:37

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

  16. 04:51

    מציענו לבנות את הפונקציה האסינכרונית, אבל איפה פה הכל בקהל? כאשר אנחנו קוראים לה, בואו נקרא לה get site, קודם כל יש לנו את ה-long calculation, long calc נקודה, אני שוב רואה ששכחתי, נחשוף אותה החוצה, זאת הסיבה שאנחנו לא רואים אותה שם.

  17. 05:15

    מודול exports, נשים את הפונקציה כאן, ועכשיו היא אמורה להיות ב-long calc get site. דאטה ואנחנו שולחים איזשהו url http://mysite.com לא של השרת הזה לאיזשהו דאטה ותביא לי משם את המספר אוקיי מה מוחזר לנו מפה?

  18. 05:46

    דן וקאץ׳ אז אני נכנס לקאץ׳ ובקאץ׳ סליחה לא לקאץ׳ אני נכנס לדן ובדן אני רוצה לבצע איזושהי פעולה וגם בקאץ׳ אני רוצה לבצע איזושהי פעולה אבל בואו לצורך הפשטות נסיים קודם כל את הקאץ'. בקאץ' כל מה שאני רוצה לעשות זה קיבלתי את ה-error ומה שאני רוצה זה console.log ולהציג את ה-error. נעשה

  19. 06:10

    את זה כמו שתמיד אנחנו עושים בצורה כזאת. console.log ולהציג את ההודעה עצמה. זה מה שאני תמיד רוצה לעשות נניח כרגע בכל מקרה של שגיאה. אבל מה אני רוצה לעשות ב-then?

  20. 06:26

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

  21. 06:47

    אז בואו נעתיק את כל, האמת כל זה, הופה, טעות גזרתי, c ונדביק את זה פה ועל הפעם נשתמש עם ה-num הראשון הזה, בואו נקרא לו num1 שלא יבלבל אותנו, כאן, ונשלח data עם num1.

  22. 07:16

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

  23. 07:30

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

לקורס המלא: קורס NodeJS אונליין בעברית

ההרצאה הקודמת: הסבר על Promise

ההרצאה הבאה: הסבר של async ועל await

הרצאות קשורות מקורסים אחרים

  • בעיית Cross Thread
  • בעיית ספירה לאינסוף
  • בעיית שדרוג ב-ReplicaSet - קוברנטיס

קורסים נוספים במסלול

  • קורס יסודות HTML - בניית אתר אינטרנט פשוט
  • קורס CSS 3 - בדגש על Flex & Grid
  • קורס Javascript כולל JQuery
  • קורס ג'אווה סקריפט מעשי - JavaScript
  • קורס TypeScript
  • קורס ריאקט - React