המחבר בחר בקרן ההקלה מקוביד-19 לקבל תרומה כחלק מתוכנית הכתיבה למענה לתרומות.
הקדמה
בימי ההתפתחות הראשונים של האינטרנט, אתרי האינטרנט היו בדרך כלל מורכבים מנתונים סטטיים בדף HTML. אך עכשיו שיישומי האינטרנט הפכו יותר אינטראקטיביים ודינמיים, הפכו פעולות אינטנסיביות יותר כמו ביצוע בקשות לרשת חיצונית לקבלת נתוני API כללי. כדי לטפל בפעולות אלו ב-JavaScript, מפתח צריך להשתמש בטכניקות תכנות אסינכרוני.
מאחר ו-JavaScript הוא שפת תכנות חד־בניינית עם מודל ביצוע סינכרוני המעבד פעולה אחת אחרי השנייה, הוא יכול לעבוד רק על משפט אחד בכל פעם. עם זאת, פעולה כמו בקשת נתונים מ-API יכולה לקחת כמות לא ידועה של זמן, תלוי בגודל הנתונים שנבקש, במהירות קשר הרשת, וגורמים אחרים. אם התקשרויות API נעשו באופן סינכרוני, הדפדפן לא יוכל לטפל בקליקים משתמש למשל, לגלול או ללחוץ על כפתור, עד שהפעולה הזו משלימה. זה ידוע כמו חסימה.
כדי למנוע את ההתנהגות של חסימה, לסביבת הדפדפן יש מספר רב של אפיונים האינטרנט ש-JavaScript יכול לגשת אליהם שהם אסינכרוניים, כלומר הם יכולים לרוץ במקביל לפעולות אחרות במקום ברצף. זה שימושי כי זה מאפשר למשתמש להמשיך להשתמש בדפדפן באופן רגיל בזמן שהפעולות האסינכרוניות מתבצעות.
כמתכנת ג'אווה סקריפט, אתה צריך לדעת איך לעבוד עם אפיונים האינטרנט האסינכרוניים ולטפל בתגובה או בשגיאה של הפעולות הללו. במאמר זה, תלמד על הלולאת האירועים, הדרך המקורית להתמודדות עם התנהגות אסינכרונית דרך קולבקים, ההוספה של ECMAScript 2015 עם בולים, והנוהג המודרני של שימוש ב-async/await
.
הקטע הזה יסביר כיצד JavaScript מתמודד עם קוד אסינכרוני באמצעות לולאת האירועים. תחילה יתבצע דמיינה של לולאת האירועים בפועל, ואז ייסברו שני הרכיבים של לולאת האירועים: המחסנית והתור.קוד JavaScript שאינו משתמש ב-API רשת אסינכרונית יבצע באופן סינכרוני – אחד אחרי השני, בצורה רצופה. זה מודגם על ידי קוד הדוגמה הזה שקורא לשלוש פונקציות שכל אחת מדפיסה מספר ל־console:// מגדיר שלוש פונקציות דוגמהבקוד זה, אתה מגדיר שלוש פונקציות שמדפיסות מספרים עם console.log()
.
לאחר מכן, יש לכתוב קריאות לפונקציות:
הפלט יתבסס על סדר הפעולות שנקראו – first()
, second()
, ואז third()
:
כאשר נעשה שימוש ב-API רשת אסינכרונית, החוקים הופכים יותר מורכבים. API מובנה שבו ניתן לנסות את זה הוא setTimeout
, שמגדיר טיימר ומבצע פעולה לאחר כמות זמן מסוימת. setTimeout
צריך להיות אסינכרוני, אחרת כל הדפדפן יישאר קפוא במהלך ההמתנה, וזה יוביל לחוויית משתמש לקויה.הוסף את setTimeout
לפונקציה second
כדי לדמות בקשה אסינכרונית:
בקוד זה, אתה מגדיר שלושה פונקציות המדפיסות מספרים עם console.log()
.
לאחר מכן, כתוב קריאות לפונקציות:
הפלט יהיה תלוי בסדר שבו קראו לפונקציות—first()
, second()
, ולאחר מכן third()
:
Output1
2
3
כאשר משתמשים ב-Web API אינטרנית, הכללים הופכים להיות יותר מסובכים. API מובנה בתוכו שאפשר לבדוק זאת עם זה הוא setTimeout
, שמקבע טיימר ומבצע פעולה לאחר כמות זמן מסוימת. setTimeout
צריך להיות אסינכרוני, אחרת כל הדפדפן יישאר קפוא במהלך ההמתנה, מה שיגרום לחוויה משתמשת גרועה.
הוסף setTimeout
לפונקציה second
כדי לדמות בקשה אסינכרונית:
setTimeout
מקבל שני טיעונים: הפונקציה שהוא ירוץ באופן אסינכרוני, ואת כמות הזמן שהוא יחכה לפני שהוא קורא לפונקציה זו. בקוד זה אתה עטף console.log
בפונקציה אנונימית והעברתה ל-setTimeout
, ואז הגדרת הפונקציה לרוץ לאחר 0
מילישניות.
עכשיו קרא לפונקציות, כפי שעשית קודם:
אולי תצפה עם setTimeout
שמוגדר ל 0
שהפעלת שלושת הפונקציות הללו עדיין תגרום למספרים להדפיס בסדר סדרתי. אך בגלל שהוא אסינכרוני, הפונקציה עם העיכוב תדפיס אחרונה:
Output1
3
2
בין אם תגדיר את העיכוב לאפס שניות או לחמישה דקות לא ישנה הבדל – ה- console.log
שנקרא על ידי קוד אסינכרוני יבצע אחרי הפונקציות הסינכרוניות העליונות. זה קורה בגלל שנטיית הסביבה של JavaScript, במקרה זה הדפדפן, משתמשת במושג הנקרא לולאת אירועים כדי לנהל עלות, או אירועים מקבילים. מאחר ו- JavaScript יכול רק לבצע משפט אחד בכל פעם, הוא זקוק ללולאת האירועים כדי להודיע מתי לבצע איזה משפט מסוים. לולאת האירועים מטפלת בזה עם המושגים של ערימה ושל תור.
ערימה
ה- ערימה, או ערימת השיחות, מחזיקה את המצב של הפונקציה הנוכחית שמתבצעת. אם אתה לא מכיר את המושג של ערימה, אפשר לדמיין אותה כמו מערך עם תכונות "אחרון ב, ראשון חוץ" (LIFO), כלומר אפשר רק להוסיף או להסיר פריטים מסוף הערימה. JavaScript ירוץ את ה- מסגרת הנוכחית (או קריאת הפונקציה בסביבה מסוימת) בערימה, ואז יסיר אותה ויעבור לאחת הבאה.
לדוגמה המכילה רק קוד סינכרון, הדפדפן מתמודד עם הביצוע בסדר הבא:
- הוספת
first()
למחסנית, הרצתfirst()
אשר מחזירה1
לתיקייה, הסרתfirst()
מהמחסנית. - הוספת
second()
למחסנית, הרצתsecond()
אשר מחזירה2
לתיקייה, הסרתsecond()
מהמחסנית. - הוספת
third()
למחסנית, הרצתthird()
אשר מחזירה3
לתיקייה, הסרתthird()
מהמחסנית.
הדוגמה השנייה עם setTimout
נראית כך:
- הוספת
first()
למחסנית, הרצתfirst()
אשר מחזירה1
לתיקייה, הסרתfirst()
מהמחסנית. - הוספת
second()
למחסנית, הרצתsecond()
.- הוספת
setTimeout()
למחסנית, הרצת אינטרנט APIsetTimeout()
אשר מתחיל טיימר ומוסיפה את הפונקציה האנונימית לתור, הסרתsetTimeout()
מהמחסנית.
- הוספת
- הסרת
second()
מהמחסנית. - הוספת
third()
למחסנית, הרצתthird()
אשר מחזירה3
לתיקייה, הסרתthird()
מהמחסנית. - הלולאה של האירועים בודקת את התור לכל מסרים בהמתנה ומוצאת את הפונקציה האנונימית מ-
setTimeout()
, מוסיפה את הפונקציה לערימה שמחזירה2
לתוך התפריט, ואז מסירה אותה מהערימה.
באמצעות setTimeout
, API אינטרנט אסיכרוני, מציג את מושג ה- תור, שהמדריך הזה יכסה בהמשך.
תור
ה- תור, המכונה גם תור המסרים או תור המשימות, הוא אזור ממתין לפונקציות. כשהערימה ריקה, הלולאה של האירועים תבדוק את התור לכל המסרים הממתינים, מהמסר העתיק ביותר. ברגע שהיא מוצאת מסר, היא מוסיפה אותו לערימה, שתבצע את הפונקציה במסר.
בדוגמא של setTimeout
, הפונקציה האנונימית פועלת מייד לאחר שהוצאה הראשית, מאחר שהזמן היה מוגדר ל- 0
שניות. �חשוב לזכור שהזמן לא אומר שהקוד יבצע בדיוק 0
שניות או בכמות הזמן שהוגדר, אלא שהוא יוסיף את הפונקציה האנונימית לתור בכמות הזמן הזו. קיומו של מערכת התור הזו קיים מכיוון שאילו הזמן היה מוסיף את הפונקציה האנונימית ישירות לערימה כשהזמן מסתיים, הוא היה משבש את כל פונקציה שמבצעת כרגע, מה שיכול לגרום לתוצאות לא רצויות ובלתי צפויות.
הערה: יש גם תור נוסף הנקרא תור העבודה או תור המשימות המיקרוסקופיות שמטפל בבטחות. משימות מיקרוסקופיות כמו בטחות מטופלות בעדיפות גבוהה יותר מאשר משימות מאקרוסקופיות כמו setTimeout
.
עכשיו אתה יודע כיצד לולאת האירוע משתמשת בערימה ובתור כדי לנהל את סדר הביצוע של הקוד. המשימה הבאה היא להבין כיצד לשלוט בסדר הביצוע בקוד שלך. כדי לעשות זאת, תלמד תחילה על הדרך המקורית להבטיח שקוד אסינכרוני מטופל כראוי על ידי לולאת האירוע: פונקציות קלטנית.
פונקציות קלטנית
בדוגמה של setTimeout
, הפונקציה עם הזמן הרגעים רצה אחרי כל דבר במסדר העבודה הראשוני העליון. אך אם אתה רוצה להבטיח שאחת הפונקציות, כמו הפונקציה שלישית
, תרוץ אחרי הזמן הרגעים, אז תצטרך להשתמש בשיטות קידוד אסינכרוני. כאן, הזמן הרגעים יכול לייצג שיחה אפיינית אסינכרונית המכילה מידע. אתה רוצה לעבוד עם המידע מהשיחה האפיינית, אך אתה צריך לוודא שהמידע מוחזר קודם.
הפתרון המקורי לטפל בבעיה זו הוא באמצעות פונקציות קולבק. לפונקציות קולבק אין תחביר מיוחד; הן פשוט פונקציה שהועברה כארגומנט לפונקציה אחרת. הפונקציה שלוקחת פונקציה אחרת כארגומנט נקראת פונקציה מסדר גבוה יותר. לפי ההגדרה זו, כל פונקציה יכולה להפוך לפונקציה קולבק אם היא מועברת כארגומנט. קולבקים אינם אסינכרוניים מטבעם, אך יכולים לשמש למטרות אסינכרוניות.
הנה דוגמה קוד תחבירית של פונקציה מסדר גבוה יותר ופונקציה קולבק:
בקוד זה, אתה מגדיר פונקציה fn
, מגדיר פונקציה higherOrderFunction
שלוקחת פונקציה callback
כארגומנט, ומעביר fn
כקולבק לhigherOrderFunction
.
ריצת הקוד הזה תיתן את הבא:
OutputJust a function
בואו נחזור לפונקציות ראשונה
, שנייה
ושלישית
עם setTimeout
. זה מה שיש לך עדיין:
המשימה היא להבטיח שהפונקציה השלישית תתעכב עד שהפעולה האסיכרונית בפונקציה השנייה תשלים. כאן באים קלאבקים. במקום לבצע את הפונקציות הראשונה, השנייה והשלישית ברמה העליונה של הביצוע, תעביר את הפונקציה השלישית כארגומנט לפונקציה השנייה. הפונקציה השנייה תבצע את הקלאבק לאחר שהפעולה האסיכרונית השלמה.
הנה שלוש הפונקציות עם קלאבק מופעל:
עכשיו, הפעל את הפונקציה הראשונה והשנייה, ואז תעביר את הפונקציה השלישית כארגומנט לפונקציה השנייה:
לאחר ריצת קובץ הקוד הזה, תקבל את הפלט הבא:
Output1
2
3
תדפיס את הראשון 1
, ואחרי שהזמן ישלים (במקרה זה, אפס שניות, אך אפשר לשנות אותו לכמות כזו) ידפיס 2
ואז 3
. על ידי העברת פונקציה כקלאבק, כבר מצאת דרך לעכב את הביצוע של הפונקציה עד שה-Web API האסיכרוני (setTimeout
) ישלים.
המפתח לקח כאן הוא שפונקציות הקלאבק אינן אסיכרוניות – setTimeout
הוא ה-Web API האסיכרוני האחראי לטפל במשימות אסיכרוניות. הקלאבק רק מאפשר לך לקבל הודעה על כך שמשימה אסיכרונית השלמה ומטפל בהצלחה או כישלון של המשימה.
עכשיו שלמדת איך להשתמש בקללבקס לניהול משימות אסיכרוניות, הסעיף הבא מסביר את הבעיות של הכנסת יותר מדי קללבקס ויצירת "פירמידת האומות."
קללבקס מקוננים ופירמידת האומות
פונקציות קללבקס הן דרך יעילה להבטיח ביצוע ממשיך של פונקציה עד שאחרת משלימה ומחזירה עם נתונים. עם זאת, בגלל הטבע המקונן של קללבקס, הקוד יכול להפוך להיות מבולגן אם יש לך המון בקשות אסיכרוניות עוקבות שתלויות זו בזו. זו הייתה מכאן גדולה עבור מפתחי JavaScript בשלב מוקדם, וכתוצאה מכך קוד המכיל קללבקס מקונן מכונה לעתים קרובות "פירמידת האומות" או "גיהינום הקללבקס".
הנה הדגמה של קללבקס מקוננים:
בקוד זה, כל setTimeout
חדש מקונן בתוך פונקציה מסדר גבוה יותר, יוצר צורת פירמידה של קללבקס יותר ויותר עמוקים. הריצה של קוד זה תיתן את הבא:
Output1
2
3
במציאות, עם קוד אסיכרוני בעולם האמיתי, זה יכול להפוך להרבה יותר מסובך. סביר שתצטרך לעשות עיכוב שגיאות בקוד אסיכרוני, ואז להעביר נתונים מתגובה אחת לבקשה הבאה. עשיו זאת עם קללבקס יכול להקשיב את הקוד שלך קשה לקריאה ולתחזוקה.
הנה דוגמה שניתנת לריצה של "פירמידת האומות" יותר מספרית שאפשר לשחק עם:
בקוד זה, עליך להבטיח שכל פונקציה תשתמש באופן אפשרי ב response
ובאופן אפשרי ב error
, מה שהופך את הפונקציה callbackHell
למבלבלת מבטיח.
הפעלת הקוד הזה תיתן לך את הבא:
Output
First 9
Second 3
Error: Whoa! Something went wrong.
at asynchronousRequest (<anonymous>:4:21)
at second (<anonymous>:29:7)
at <anonymous>:9:13
דרך זו לניהול קוד אסימכרוני קשה לעקיבא. כתוצאה מכך, הצגת המושג בטחונות ב- ES6. זהו הנושא של הסעיף הבא.
בטחונות
A promise represents the completion of an asynchronous function. It is an object that might return a value in the future. It accomplishes the same basic goal as a callback function, but with many additional features and a more readable syntax. As a JavaScript developer, you will likely spend more time consuming promises than creating them, as it is usually asynchronous Web APIs that return a promise for the developer to consume. This tutorial will show you how to do both.
יצירת בטחון
אפשר לאתחל תשובה בעזרת התחביר new Promise
, ועליך לאתחל אותה עם פונקציה. הפונקציה שמועברת לתשובה מכילה פרמטרים resolve
ו-reject
. הפונקציות resolve
ו-reject
מטפלות בהצלחה ובכישלון של פעולה, בהתאמה.
כתוב את השורה הבאה כדי להכריז על תשובה:
אם תבדוק את התשובה המאותחלת במצב זה בתיבת התוכנית של הדפדפן שלך, תמצא שיש לה סטטוס pending
וערך undefined
:
Output__proto__: Promise
[[PromiseStatus]]: "pending"
[[PromiseValue]]: undefined
עד כה, לא נקבע שום דבר עבור התשובה, ולכן היא תשאר שם במצב pending
לנצח. הדבר הראשון שאפשר לעשות כדי לבדוק תשובה הוא להספיק את התשובה על ידי פתרון עם ערך:
עכשיו, על ידי בדיקת התשובה, תמצא שיש לה סטטוס של fulfilled
, וערך value
המוגדר לערך שהעברת ל-resolve
:
Output__proto__: Promise
[[PromiseStatus]]: "fulfilled"
[[PromiseValue]]: "We did it!"
כפי שצויין בתחילת הסעיף, תשובה היא אובייקט שעשוי להחזיר ערך. לאחר שהושלמה בהצלחה, הערך value
עובר מ-undefined
להיות מלא בנתונים.
A promise can have three possible states: pending, fulfilled, and rejected.
- Pending – המצב הראשוני לפני שהוכרע או נדחה
- Fulfilled – פעולה מוצלחת, התשובה התגברה
- Rejected – פעולה נכשלה, התשובה נדחתה
לאחר השלמה או דחייה, תשובה מגובשת.
עכשיו שיש לך מושג על איך נוצרות הבטחות, בוא נבחן איך מפתח עשוי לצרוך את הבטחות אלו.
צריכת הבטחה
הבטחה בחלק האחרון התגשמה עם ערך, אך אתה גם רוצה להיות מסוגל לגשת לערך. לבטחות יש שיטה הנקראת then
שתרוץ אחרי שהבטחה מגיעה ל resolve
בקוד. then
יחזיר את הערך של הבטחה כפרמטר.
ככה תחזיר ותישאיר את value
של הבטחה הדוגמא:
הבטחה שיצרת היתה עם [[PromiseValue]]
של We did it!
. ערך זה הוא מה שיעבור לפונקצית האנונימית כ response
:
OutputWe did it!
עד כה, הדוגמא שיצרת לא כללה API אינטרנט אסינכרוני – היא רק הסבירה איך ליצור, לפתור ולצרוך בטחה ב-JavaScript המקורי. באמצעות setTimeout
, אתה יכול לבדוק בקשה אסינכרונית.
הקוד הבא מדמה נתונים שהוחזרו מבקשה אסינכרונית כבטחה:
באמצעות תחביר then
מבטיח שה response
יישאר רק כאשר הפעולה setTimeout
תשלים אחרי 2000
מילישניות. כל זה נעשה מבלי לחפור בקללאבים.
עכשיו אחרי שני שניות, זה יתמתת את ערך ההבטחה וזה יישוחרר ב then
:
OutputResolving an asynchronous request!
הבטחות יכולות גם להיות מקושרות כדי להעביר מידע ליותר מפעולה אסינכרונית אחת. אם ערך מוחזר ב then
, ניתן להוסיף then
נוסף שיתמתת עם ערך ההחזרה של then
הקודם:
התגובה המתמתת בשני then
תישתחרר את ערך ההחזרה:
OutputResolving an asynchronous request! And chaining!
מאחר ש then
יכול להיות מקושר, זה מאפשר לצרכן הבטחות להיראות יותר סינכרוני מקולבקים, מאחר שאינם צריכים להיות מקוננים. זה יאפשר קוד קריא יותר שניתן לתחזק ולאמת בקלות רבה יותר.
להתמודדות עם שגיאות
עד כה, עסקת רק בהבטחה עם resolve
מוצלח, מה שמכניס את ההבטחה למצב fulfilled
. אך לעתים קרובות עם בקשה אסינכרונית עליך גם להתמודד עם שגיאה – אם ה-API מופסק, או שנשלחה בקשה מוטעית או לא מורשית. הבטחה צריכה להיות מסוגלת להתמודד גם עם שני המצבים. בסעיף זה, תיצור פונקציה כדי לבדוק את מקרי ההצלחה והכישלון של יצירה וצריכה של הבטחה.
פונקציה זו getUsers
תעביר דגל להבטחה, ותחזיר את ההבטחה:
קבע את הקוד כך שאם onSuccess
הוא true
, הפיקדון יספק עם נתונים מסוימים. אם false
, הפונקציה תדחה עם שגיאה:
לתוצאה המוצלחת, אתה מחזיר אובייקטים JavaScript המייצגים נתוני משתמש דוגמא.
על מנת להתמודד עם השגיאה, תשתמש בשיטת המתנדב catch
. זה ייתן לך קלאס כישלון עם הerror
כפרמטר.
הרץ את הgetUser
בפקודה עם onSuccess
מוגדר לfalse
, באמצעות השיטה then
עבור המקרה המוצלח והשיטה catch
עבור השגיאה:
מאחר והשגיאה נכשלה, הthen
ידועך והcatch
יטפל בשגיאה:
OutputFailed to fetch data!
אם תחליף את הדגל וresolve
במקום זאת, הcatch
יתעלם, והנתונים יחזרו במקום זאת:
זה ייצא את נתוני המשתמש:
Output(3) [{…}, {…}, {…}]
0: {id: 1, name: "Jerry"}
1: {id: 2, name: "Elaine"}
3: {id: 3, name: "George"}
לצורך ההתייחסות, הנה טבלה עם שיטות המטפל על אובייקטים Promise
:
Method | Description |
---|---|
then() |
Handles a resolve . Returns a promise, and calls onFulfilled function asynchronously |
catch() |
Handles a reject . Returns a promise, and calls onRejected function asynchronously |
finally() |
Called when a promise is settled. Returns a promise, and calls onFinally function asynchronously |
אחד מ-API-ים הרשת הכי שימושיים ונפוצים שמחזירים הבטחה הוא Fetch API, שמאפשר לך לבצע בקשת משאב אסינכרונית דרך הרשת. fetch
הוא תהליך משולב שנדרש לשרשור then
. דוגמה זו מדגימה איך לגשת ל-API של GitHub כדי לאחזר נתוני משתמש, ובנוסף לטפל בשגיאות פוטנציאליות:
// לאחזר משתמש מ-API של GitHub
הבקשה fetch
נשלחת ל-URL של https://api.github.com/users/octocat
, שמחכה אסינכרונית לתגובה. ה-then
הראשון מעביר את התגובה לפונקציה אנונימית שמעצבת את התגובה כ-נתוני JSON, ואז מעביר את ה-JSON ל-then
שני שמפעיל את הנתונים ללוג. ההצהרה של catch
מקבלת כל שגיאה ומפעילה אותה ללוג. הרצת קוד זה תחזיר את התוצאה הבאה:
זהם הנתונים שביקשו מ-https://api.github.com/users/octocat
, בתבנית JSON.
הבקשה של fetch
נשלחת לכתובת ה-https://api.github.com/users/octocat
של GitHub, שמחכה אסיכרונית לתגובה. הפעולה then
הראשונה מעבירה את התגובה לפונקציה נוספת שמעצבת את התגובה כ-נתוני JSON, ואז מעבירה את ה-JSON לפעולה then
השנייה שמדפיסה את הנתונים לתיקייה. הפעולה catch
מדפיסה כל שגיאה לתיקייה.
הריצה של הקוד הזה תיצור את התוצאות הבאות:
Outputlogin: "octocat",
id: 583231,
avatar_url: "https://avatars3.githubusercontent.com/u/583231?v=4"
blog: "https://github.blog"
company: "@github"
followers: 3203
...
זהו הנתונים שנבקשו מ-https://api.github.com/users/octocat
, המוצגים בפורמט JSON.
חלק זה מהדרכה הדגיש שהבטחות משלבות הרבה שיפורים עבור עבודה עם קוד אסינכרוני. אך, בעוד שהשימוש ב-then
לטפל בפעולות אסינכרוניות קל יותר לעקיבה מאשר הפיתגורת של קולבקים, יש מפתחים שעדיין מעדיפים פורמט סינכרוני של כתיבת קוד אסינכרוני. כדי לטפל בצורך זה, ECMAScript 2016 (ES7) הציג את פונקציות async
ואת מילת המפתח await
כדי להקל על עבודה עם הבטחות.
פונקציות אסינכרוניות עם async/await
פונקציית async
מאפשרת לך להתמודד עם קוד אסינכרוני בצורה שנראית סינכרונית. פונקציות async
עדיין משתמשות בהבטחות מאחורי הקלעים, אבל יש להן תחביר ג'אווה סקריפט מסורתי יותר. בחלק זה תנסה דוגמאות של תחביר זה.
אתה יכול ליצור פונקציית async
על ידי הוספת מילת המפתח async
לפני פונקציה:
למרות שפונקציה זו אינה מתמודדת עדיין עם משהו אסינכרוני, היא מתנהגת באופן שונה מפונקציה מסורתית. אם תבצע את הפונקציה, תגלה שהיא מחזירה הבטחה עם [[PromiseStatus]]
ו-[[PromiseValue]]
במקום ערך החזרה.
נסה זאת על ידי רישום קריאה לפונקציית getUser
:
זה ייתן את הדברים הבאים:
Output__proto__: Promise
[[PromiseStatus]]: "fulfilled"
[[PromiseValue]]: Object
משמעות הדבר היא שניתן לטפל בפונקציית async
עם then
באותו אופן שניתן לטפל בהבטחה. נסה זאת עם הקוד הבא:
קריאה זו לפונקציית getUser
מעבירה את ערך ההחזרה לפונקציה אנונימית שרושמת את הערך לקונסולה.
תקבל את הדברים הבאים כאשר תפעיל את התוכנית:
Output{}
פונקציית async
יכולה להתמודד עם הבטחה שנקראת בתוכה באמצעות האופרטור await
. ניתן להשתמש ב-await
בתוך פונקציית async
והוא ימתין עד שההבטחה תתיישב לפני ביצוע הקוד המיועד.
עם ידע זה, תוכל לשכתב את בקשת Fetch מהחלק האחרון באמצעות async
/await
כדלקמן:
האופרטורים await
כאן מבטיחים שהנתונים (data
) לא יועברו ללוג לפני שהבקשה תמלא אותם בנתונים.
כעת הנתונים הסופיים (data
) ניתנים לטיפול בתוך פונקציית getUser
, ללא צורך בשימוש ב־then
. זהו פלט הלוג של data
:
Outputlogin: "octocat",
id: 583231,
avatar_url: "https://avatars3.githubusercontent.com/u/583231?v=4"
blog: "https://github.blog"
company: "@github"
followers: 3203
...
הערה: בסביבות רבות, שימוש ב־async
הוא נחוץ לשימוש ב־await
—אך, גרסאות חדשות של דפדפנים ושל Node מאפשרות שימוש ב־await
ברמה העליונה, מה שמאפשר לעבור על יצירת פונקציה אסינכרונית שתקיף את ה־await
.
לבסוף, מכיוון שאתה טופל ב־promise המוחלט בתוך הפונקציה האסינכרונית, תוכל גם לטפל בשגיאה בתוך הפונקציה. במקום להשתמש בשיטת catch
עם then
, תשתמש בתבנית try
/catch
לטיפול בשגיאה.
הוסף את הקוד המודגש הבא:
התוכנית תדלג כעת לבלוק ה־catch
אם תקבל שגיאה ותלוג את השגיאה הזו לקונסול.
הקוד המודרני האסינכרוני ב-JavaScript מטופל לרוב באמצעות תחביר async
/await
, אבל חשוב להבין איך הבטחות (promises) עובדות, במיוחד מכיוון שהן מסוגלות לספק תכונות נוספות שלא ניתנות לטיפול באמצעות async
/await
, כמו שילוב הבטחות עם Promise.all()
.
הערה: ניתן לשחזר את התחביר async
/await
באמצעות גנרטורים בשילוב הבטחות כדי להוסיף גמישות לקוד שלך. כדי ללמוד עוד, עיין במדריך שלנו הבנת גנרטורים ב-JavaScript.
סיכום
מכיוון ש- Web APIs מספקות נתונים בצורה אסינכרונית לעיתים קרובות, למידה כיצד להתמודד עם תוצאות פעולות אסינכרוניות היא חלק הכרחי מהיותך מפתח JavaScript. במאמר זה, למדת כיצד סביבת האירוח משתמשת בלולאת האירועים כדי לטפל בסדר הביצוע של הקוד עם הערימה ו-התור. ניסית גם דוגמאות לשלוש דרכים להתמודד עם הצלחה או כישלון של אירוע אסינכרוני, עם פונקציות התקשרות חזרה (callbacks), הבטחות (promises), ותחביר async
/await
. לבסוף, השתמשת ב- Fetch Web API כדי לטפל בפעולות אסינכרוניות.
למידע נוסף על כיצד הדפדפן מטפל באירועים מקבילים, קרא את מודל המקבילות ולולאת האירועים ברשת המפתחים של מוזילה. אם תרצה ללמוד עוד על JavaScript, חזור לסדרת כיצד לקודד ב-JavaScript שלנו.