JS Promises

הסבר על אחד הפיצ'רים השימושיים של JavaScript שמאפשר ניהול קל ונעים של משימות אסינכרוניות.
JavaScript code of promises JS

JS Promises הוא פיצ'ר של EcmaScript 6. ניתן להשתמש בו כמובן ב-Node.JS ואפילו בצד הלקוח בכל הדפדפנים חוץ מאינטרנט אקספלורר כמובן (כל הגרסאות).

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

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

object.save({ key: value }, {
  success: function(object) {
    // the object was saved. lets do something!
    doSomething(function(result) {
     //doing something and then, when complete, we will do another thing
       doAnotherThing(function(result) {
       //and the party goes on!
        });
     });
  },
  error: function(object, error) {
    // saving the object failed.
  }
});

יש דרכים להמנע מהדבר הזה, אבל עם js promises הרבה יותר קל לעשות את זה. בואו ונראה איך!

בגדול promises זה אובייקט חביב שמקבל פונקציה עם שני פרמטרים: resolve ו reject. בתוך ה-promise אנחנו יכולים לעשות הכל, אבל הכל, אבל ממש הכל. כשאנחנו מסיימים אנחנו מחזירים resolve (אפשר עם פרמטרים) במקרה והכל מצוין, או reject במידה והכל נכשל. ככה זה נראה:

  var myPromise = new Promise(function(resolve, reject) {
        resolve(paramater); // Promise resolved! :)
        reject(parameter2); // Promise rejected! :(
    };
  });


 myPromise.then(function(paramater) {
    console.log('Got data! Promise fulfilled.');
  }, function(parameter2) {
    console.log('Promise rejected.');
  })

יש כאן שני חלקים – ה-promise שעוטף בעצם את הפעולה עצמה – במקרה הזה אין ממש פעולה, מה שחשוב זה להחזיר את resolve ואת reject.
החלק השני הוא מה אני עושה כאשר ה-promise נכשל או מצליח. וזה החלק השני – אני משתמש ב-then שמקבלת שני פרמטרים – פונקציה אנונימית ראשונה שהיא רצה כאשר יש לנו resolve ופונקציה שניה שרצה כאשר יש לנו reject.

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

  var promise = new Promise(function(resolve, reject) {
    var request = new XMLHttpRequest();
 
    request.open('GET', 'http://api.icndb.com/jokes/random');
    request.onload = function() {
      if (request.status == 200) {
        resolve(request.response); // we got data here, so resolve the Promise
      } else {
        reject(Error(request.statusText)); // status is not 200 OK, so reject
      }
    };
 
    request.onerror = function() {
      reject(Error('Error fetching data.')); // error occurred, reject the  Promise
    };
 
    request.send(); //send the request
  });

 promise.then(function(data) {
    console.log('Got data! Promise fulfilled.');
    document.getElementsByTagName('body')[0].textContent = JSON.parse(data).value.joke;
  }, function(error) {
    console.log('Promise rejected.');
    console.log(error.message);
  })

הפעם בתוך ה-promise יש לנו אשכרה קוד שעושה משהו. במקרה הזה שולח בקשה ל-API של בדיחות (נשבע לכם). במידה והבקשה מצליחה, אנחנו מקבלים 200 ואז מפעילים את ה-resolve ומעבירים כפרמטר את התגובה. במידה והבקשה נכשלת, אנו מעבירים reject עם השגיאה.

בחלק השני, אנו קובעים מה עושים כאשר יש הצלחה (פונקציה אנונימית ראשונה ב-then) ומה קורה אם זה נכשל (פונקציה אנונימית שניה).

טוב, עד כאן ממש מגניב, אבל מה יעיף לכם את הסכך באמת? רואים את ה-then הזה? אפשר להעביר בו שני פרמטרים של הצלחה וכשלון, אבל לא דיברנו על מה שהוא מחזיר. מה הוא מחזיר אתם שואלים? האם הוא מחזיר אהבת אמת? לא. משהו יותר טוב! מה יכול להיות יותר טוב מאהבת אמת? התשובה היא: עוד promise! ואליו אפשר לשרשר עוד then. איך? משהו בסגנון הזה:

 var myPromise = new Promise(function(resolve, reject) {
        resolve(paramater); // Promise resolved! :)
        reject(parameter2); // Promise rejected! :(
    };
  });


 myPromise.then(function(paramater) {
    console.log('Got data! Promise fulfilled.');
    return data;
  }, function(parameter2) {
    console.log('Promise rejected.')
.then(function(data){
   //do another thing, it will be called after the first promise was fullfilled.
}).
.then(function(data){
   //do third thing, it will be called after the last promise was fullfilled.
});

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

if(window.Promise){
      console.log('Promise found');
      var promise=new Promise(function(resolve,reject){
            var request = new XMLHttpRequest();
            request.open('GET', 'http://api.icndb.com/jokes/random');
            request.onload = function() {
              if (request.status == 200) {
                resolve(request.response); //we get the data here.So, resolve the Promise
              }
              else {
                reject(Error(request.statusText)); //if status is not 200 OK, reject.
              }
            };
        
            request.onerror = function() {
              reject(Error("Error fetching data.")); //error occurred, reject the Promise
            };
        
            request.send(); //send the request
      });
              
      console.log('Asynchronous request made.');
    
      promise.then(function(data){
            console.log('Got data! Promise fulfilled.');
            document.getElementsByTagName('body')[0].textContent=JSON.parse(data).value.joke;
            return 'Laugh level - very funny!';
          },function(error){
            console.log('Promise rejected.');
            console.log(error.message);
      })
      .then(function(data){
        console.log('success : '+data);
      });

    }
    else
        console.log('Promise not available');

הנה קישור לדוגמה שעובדת – אתם מוזמנים לשחק שם וליצור גרסה משלכם!

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

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

פוסטים נוספים שכדאי לקרוא

פתרונות ומאמרים על פיתוח אינטרנט

המנעו מהעלאת source control לשרת פומבי

לא תאמינו כמה אתרים מעלים את ה-source control שלהם לשרת. ככה תמצאו אותם וגם הסבר למה זה רעיון רע.

בינה מלאכותית

להריץ ממשק של open-webui על הרספברי פיי

להפעיל ממשק של צ׳אט ג׳יפיטי שאפשר לגשת אליו מכל מחשב ברשת הביתית על רספברי פיי עם מודל בשם tinydolphin שרץ על רספברי פיי.

תמונת תצוגה של מנעול על מחשב
פתרונות ומאמרים על פיתוח אינטרנט

הגנה מפני XSS עם Trusted Types

תכונה ב-CSP שמאפשרת מניעה כמעט הרמטית להתקפות XSS שכל מפתח ווב צריך להכיר וכדאי שיכיר.

גלילה לראש העמוד