אסינכרוניות בג'אווה סקריפט - Promises
- Published on
- Authors
- Name
- Yonatan Snir
הקדמה
חלק שני מתוך שלושה על תכנות אסינכרוני ב-JavaScript, אולי אחד הנושאים הכי חשובים בשפה. החלק השני מתמקד בדרך היותר מקובלת היום להתמודד עם פונקציות אסינכרוניות. נלמד לכתוב פונקציות אסינכרוניות בעזרת האובייקט Promise אשר הוצג לנו לראשונה ב-ES6 ונראה איך האובייקט עוזר לנו לפשט ולסדר את הקוד כך שיהיה יותר ברור וקריא.
אז... מה זה בעצם Promise?
בתרגום לעברית Promise = הבטחה. מה זה אומר בעצם? דמיינו אימא שבאה לילד שלה ומבטיחה לו מחשב חדש. הילד מאושר והדבר הראשון שהוא עושה זה לסדר את החדר ולהכין מקום למחשב. הוא לא יודע בדיוק מתי היא תקנה לו את המחשב, אבל את החדר הוא כבר מסדר. יכול להיות שאחרי שבוע האימא תלך לקנות את המחשב, יכול להיות שהילד יתנהג לא יפה לאחותו אימא תכעס ותחליט בסוף כעונש לא לקנות לו את המחשב. אבל החדר כבר סודר בכל מקרה… זאת בדיוק המהות של Promise. אנחנו יוצרים אובייקט ומכינים מקום להגעה של נתונים. יכול להיות שהבקשה לשרת תתקבל המידע יחזור ואותו אנחנו נצטרך לנהל (האימא הלכה לקנות את המחשב והביאה אותו לילד), ויכול להיות מצב אחר בו יש שגיאה בשרת או כל תקלה אחרת והמידע לבסוף לא מגיע (האימא כעסה והחליטה לא לקנות לבסוף את המחשב), ועכשיו נצטרך לראות מה אנחנו עושים עם המקום שפנינו למחשב…
ל-Promise שלושה מצבים:
- ממתין ל… – Pending: הילד לא יודע אם הוא יקבל את המחשב או מתי.
- הושלם – Fulfilled: האימא הלכה לקנות את המחשב.
- נדחה – Rejected: האימא מאוד כועסת והחליטה לא ללכת לקנות את המחשב.
תזכורת קטנה
function getData(callback, errCallback){
setTimeout(() => {
if (true){
callback('Ok, everything wend good')
} else {
errCallback('Ohh no!!! Something got lost...')
}
},2000)
}
getData(
msg => console.log(msg),
err => console.log(err)
)
זוכרים? יש לנו את הפונקציה getData
שמבצעת "קריאה" לשרת. אם הכל הלך טוב נעטוף בפונקציה "callback" את המידע. אם קרה משהו לא תקין בדרך – נתונים לא נכונים או שרת שמסרב להתחבר נניח, נעטוף את השגיאה ב-errCallback. כאשר אנו מבצעים את הקריאה לפונקציה getData
, אנחנו שולחים בתוך הארגומטרים שלה 2 פונקציות, אחת תטפל במצב שחזר לנו מידע תקין והשנייה במצב של שגיאה. עכשיו בואו נמיר את הקוד הזה לאובייקט Promise. אובייקט פרומיס מקבל פונקציה עם 2 ארגומנטים. ארגומנט ראשון זוהי פונקציה שתפקידה להחזיר את המידע התקין (callback), והארגומנט השני זוהי פונקציה שתפקידה להחזיר את השגיאה (errCallback). הרעיון אותו הרעיון ודיי דומה לקוד עם הקולבקים. בואו נסתכל:
let prom = new Promise((resolve, reject) => {
setTimeout(() => {
if (true){
resolve('Ok, everything wend good');
} else {
reject('Ohh no!!! Something got lost...')
}
},2000)
})
מה עשינו? יצרנו משתנה חדש בשם prom
, והכנסו לתוכו אובייקט פרומיס חדש. (new Promise
) כמו שאמרנו, פרומיס מקבל פונקציה עם 2 ארגומטרים אחת לטיפול בבקשות שצלחו resolve ואחת לטיפול בבקשות שניכשלו (reject). עכשיו כל שנותר הוא לקרוא לפרומיס הזה ולהתחיל לטפל בתשובות שחוזרות "מהשרת" באמצעות .then
. שזה אומר בפשטות: אחרי שהקריאה לשרת התבצעה והמידע חזר – אז תעשה כך וכך, ואם יש שגיאה "תפוס אותה" שאת זה אנחנו עושים באמצעות .catch
כמו שאתם יכולים לנחש.
prom
.then(msg => console.log(msg))
.catch(err => console.log(err))
זוכרים את ה-"Callback Hell" ? אז עכשיו במקרה של כמה בקשות אסינכרוניות שמתבצעות אחת אחרי השניה, אפשר לטפל בהם באמצעות Promise בצורה הפשוטה והברורה הזאת:
prom
.then(data => {
//code goes here
})
.then(anotherData => {
//code goes here
})
.then(() => {
//code goes here
})
.then(() => {
//code goes here
})
.catch(() => {
//code goes here
})
וזה כבר קוד שהרבה יותר קל לדבג לעקוב ולהבין מה בכלל קורה.
במקרה שלנו הכנסו את Promise לתוך משתנה. אבל כמובן, אפשר גם להחזיר אותו מתוך פונקציה ולבצע אליה קריאה.
const getData = () => {
return new Promise(resolve => {
// code goes here
})
}
getData() // we call the function.
.then(data => {
// code goes here.
})
וזה כמובן הבסיס להבנה של Promise. בחלק הבא והאחרון נלמד את הסינטקס הכי חדשני ומעודכן לכתיבת פרומיסים בצורה אפילו ברורה וקלה יותר. הסינטקס של ה Async await אשר הוצג ב ES8 .