אינטרנט ישראל
  • ראשי
  • אודות רן בר-זיק ואינטרנט ישראל
  • ערוץ טלגרם
  • מסטודון
  • התחברו אלי בטוויטר
  • התחברו אלי בלינקדאין
  • ספר ג'אווהסקריפט
  • ראשי
  • אודות רן בר-זיק ואינטרנט ישראל
  • ערוץ טלגרם
  • מסטודון
  • התחברו אלי בטוויטר
  • התחברו אלי בלינקדאין
  • ספר ג'אווהסקריפט
ראשי » מדריכים » Node.js » מדריך Node.js: קוד אסינכרוני מותנה ומקבילי

מדריך Node.js: קוד אסינכרוני מותנה ומקבילי

רן בר-זיק אוקטובר 14, 2014 7:43 am תגובה אחת

כמה דרכים ליצור פונקציות אסינכרוניות ב-Node.js

כדאי תמיד להשאר מעודכנים! אם יש לכם טלגרם, בדקו את ערוץ הטלגרם של האתר שבו אני מעדכן על פוסטים חדשים 🙂 אם אתם רוצים ללמוד תכנות באופן מקיף ומסודר, הצטרפו לאלפי הלומדים בפרויקט "ללמוד ג'אווהסקריפט בעברית" שמלמד לתכנת בג'אווהסקריפט, ב-Node.js ובריאקט וגם מלמד על תרומה לקוד פתוח. גם ספרים דיגיטליים וגם ספרים מודפסים. בשיתוף הקריה האקדמית אונו ובתמיכת חברות מובילות כגון Wix, Outbrain, Elementor, Iron Source, Chegg, Really Good ועוד.

אוהבים את מדריך Node.js? רוצים לדעת עוד?

ספר מקיף על Node.js, בעברית, שנכתב על ידי רן בר-זיק וכולל תרגילים רבים ומידע מקיף - גם על מודולים אסינכרוניים וגם על CLI וסטרימים ומידע רב יותר על Node.js ניתן להורדה ממש פה.
כדאי תמיד להשאר מעודכנים! אם יש לכם טלגרם, בדקו את ערוץ הטלגרם של האתר שבו אני מעדכן על פוסטים חדשים 🙂 אם אתם רוצים ללמוד תכנות באופן מקיף ומסודר, הצטרפו לאלפי הלומדים בפרויקט "ללמוד ג'אווהסקריפט בעברית" שמלמד לתכנת בג'אווהסקריפט, ב-Node.js ובריאקט וגם מלמד על תרומה לקוד פתוח. גם ספרים דיגיטליים וגם ספרים מודפסים. בשיתוף הקריה האקדמית אונו ובתמיכת חברות מובילות כגון Wix, Outbrain, Elementor, Iron Source, Chegg, Really Good ועוד.

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

כל הדוגמאות שאני משתמש בהן פה הובאו מ: Understanding the node.js loop.

קוד אסינכרוני מותנה

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

על מנת להדגים, אני אראה קוד שמשתמש ב-fs (בדיוק כמו הקוד הקודם) – המודול של Node.js לטיפול בקבצים. ראשית קוד סינכרוני:


var fs = require('fs');

oldFilename = "./processId.txt";
newFilename = "./processIdOld.txt";

fs.chmodSync(oldFilename, 777);
fs.renameSync(oldFilename, newFilename);
isSymLink = fs.lstatSync(newFilename).isSymbolicLink();
console.log("The file is symbolic link? "+isSymLink);

מה הקוד הזה עושה? הוא לוקח קובץ בשם processId.txt:
1. משנה לו את ההרשאות ל-777.
2. משנה את השם שלו.
3. בודק אם השם החדש הוא לינק סימבולי (מן הסתם לא, אבל זה לא משנה).

הפעולות תלויות אחת בשניה. אם אני אנסה לשנות את השם של הקובץ לפני שאני אשנה את ההרשאות שלו ל-777, הפעולה תכשל. אם אני אבדוק את שם הקובץ החדש לפני שעשיתי שינוי שם, גם כן הפעולה תכשל. כלומר יש חשיבות עצומה לסדר הפעולות. איך אני יוצר מזה קוד אסינכרוני? בעצם כל מה שאני צריך לעשות זה ליצור שלוש callbacים. מההתחלה לסוף – קודם כל, שינוי הרשאה. שינוי ההרשאה מתבצע? מעולה! הוא יורה callback שעושה שינוי שם. שינוי השם מתבצע? מעולה. הוא יורה callback שבודק לינק סימבולי.

איך זה נראה? ככה:


var fs = require('fs');

oldFilename = "./processId.txt";
newFilename = "./processIdOld.txt";

fs.chmod(oldFilename, 777, function (err) {   
    fs.rename(oldFilename, newFilename, function (err) {
        fs.lstat(newFilename, function (err, stats) {
            var isSymLink = stats.isSymbolicLink();
            console.log("The file is symbolic link? "+isSymLink);
        });
    });
});

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

קוד אסינכרוני שרץ במקביל

אנחנו יכולים להשתמש בקוד אסינכרוני גם למקבל משימות – כלומר להריץ משימות במקביל. לא במובן של concurrent (כלומר שרץ באותו הזמן) אלא במובן של זרימת קוד – רץ באותו קטע קוד. בוא נסתכל על הקוד הסינכרוני הזה למשל:


var fs = require('fs');

function calculateByteSize() {
    var totalBytes = 0,
        i,
        filenames,
        stats;
    filenames = fs.readdirSync(".");
    for (i = 0; i < filenames.length; i ++) {
        stats = fs.statSync("./" + filenames[i]);
        totalBytes += stats.size;
    }
    console.log(totalBytes);
}

calculateByteSize();

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

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


var fs = require('fs');

var count = 0,
    totalBytes = 0;

function calculateByteSize() {
    fs.readdir(".", function (err, filenames) {
        var i;
        count = filenames.length;

        for (i = 0; i < filenames.length; i++) {
            fs.stat("./" + filenames[i], function (err, stats) {
                totalBytes += stats.size;
                count--;
                if (count === 0) {
                    console.log(totalBytes);
                }
            });
        }
    });
}

calculateByteSize();

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

מה שיש בקוד הזה, בנוסף לאסינכרניות מקבילה הוא גם שימוש ב-closure – למי שלא מכיר, כדאי לקרוא על closure במאמר שכתבתי. אבל בגדול זה היכולת של הפונקציות הפנימיות לקרוא למשתנים שזמינים לפונקציות שקראו להם. זו אחת התכונות השימושיות של JavaScript – אם יש משתנה שהוגדר ב-scope של פונקציה א', הוא יהיה זמין גם לפונקציה ב' (או callback) שנקרא ממנה.

קוד אסינכרוני כפונקציה

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

אני אדגים באמצעות פונקציה אסינכרונית מהסוג הזה:


var fs = require('fs');

var path1 = "./",
    path2 = ".././",
    logCount;

function countFiles(path, callback_function) {
    fs.readdir(path, function (err, filenames) {
        callback_function(err, path, filenames.length);
    });
}

logCount = function (err, path, count) {
    console.log(count + " files in " + path);
};

countFiles(path1, logCount);
countFiles(path2, logCount);

אני מגדיר את countFiles עם ארגומנט שנקרא callback_function. שימו לב ש-countFiles היא פונקציה רגילה לחלוטין. בתוך הפונקציה יש קריאה ל-fs.readdir שמקבלת את ארגומנט path וכיאה וכיאות לפונקציה אסינכרונית היא גם כוללת פונקציה אנונימית כ-callback. כשה-callback האנונימי נורה, מיד אחרי ש-fs.readdir מסתיימת – אז אני יכול להתמש ב-callback_function שהיא בעצם שם הפונקציה. איך callback_function זמין ל-callback? רק בגלל ה-closure.
הכל מופעל עם countFiles. אני מעביר לה שני ארגומנטים – אחד מהם הוא שם הפונקציה, או ה-callback_function, שאני רוצה להעביר – שמו בישראל logCount והוא עושה את המסלול שתיארתי ממש עכשיו. עובר ל-countFiles כארגומנט ונקרא בתוך ה-callback של fs.readdir.

לסיכום: קוד אסינכרוני הוא קוד שקשה להבין אותו בהתחלה – לוקח זמן להבין למה צריך את ה-callback, איך ה-scoping עובד ואיך להעביר משתנים מה-scope הכללי אל ה-scope של ה-callback. אבל התוצאה היא, לפחות ב-Node.js, קוד שרץ מאוד מאוד מהר – כיוון שכל הפעולות של ה-Input Output (למערכת הקבצים, למסד הנתונים וכו') רצות והקוד שלי לא מחכה להן.

במאמר הבא נדבר על require.

⚠️ תזכורת – המדריכים האלו הם רק טעימה, בספר שלי "ללמוד Node.js בעברית" יש הסברים מלאים ומקיפים על השפה המיועדים ללימוד עצמי. עם תרגילים והסברים. הספר יצא לאור בשיתוף הקריה האקדמית אונו ובתמיכת החברות אלמנטור, ו-Iron source ונערך טכנית על ידי בנג'י גרינבאום (מפתח ליבה של Node.js), גיל פינק ומתכנתים מעולים נוספים. 

כדאי תמיד להשאר מעודכנים! אם יש לכם טלגרם, בדקו את ערוץ הטלגרם של האתר שבו אני מעדכן על פוסטים חדשים 🙂 אם אתם רוצים ללמוד תכנות באופן מקיף ומסודר, הצטרפו לאלפי הלומדים בפרויקט "ללמוד ג'אווהסקריפט בעברית" שמלמד לתכנת בג'אווהסקריפט, ב-Node.js ובריאקט וגם מלמד על תרומה לקוד פתוח. גם ספרים דיגיטליים וגם ספרים מודפסים. בשיתוף הקריה האקדמית אונו ובתמיכת חברות מובילות כגון Wix, Outbrain, Elementor, Iron Source, Chegg, Really Good ועוד.
כדאי תמיד להשאר מעודכנים! אם יש לכם טלגרם, בדקו את ערוץ הטלגרם של האתר שבו אני מעדכן על פוסטים חדשים 🙂 אם אתם רוצים ללמוד תכנות באופן מקיף ומסודר, הצטרפו לאלפי הלומדים בפרויקט "ללמוד ג'אווהסקריפט בעברית" שמלמד לתכנת בג'אווהסקריפט, ב-Node.js ובריאקט וגם מלמד על תרומה לקוד פתוח. גם ספרים דיגיטליים וגם ספרים מודפסים. בשיתוף הקריה האקדמית אונו ובתמיכת חברות מובילות כגון Wix, Outbrain, Elementor, Iron Source, Chegg, Really Good ועוד.

אוהבים את מדריך Node.js? רוצים לדעת עוד?

ספר מקיף על Node.js, בעברית, שנכתב על ידי רן בר-זיק וכולל תרגילים רבים ומידע מקיף - גם על מודולים אסינכרוניים וגם על CLI וסטרימים ומידע רב יותר על Node.js ניתן להורדה ממש פה.
למאמר הקודם בסדרת המדריכים על Node.jsמדריך Node.js: קוד אסינכרוני
למאמר הבא בסדרת המדריכים על Node.jsמדריך Node.js: שימוש ב-require
לכל המאמרים במדריך
node.js

תגובה אחת

  1. יוסי הגב אוגוסט 26, 2018 בשעה 10:44 am

    בבקשה תעשה מבוא ל NODE.JS

השארת תגובה

ביטול

ללמוד ג'אווהסקריפט בעברית

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

רשימת הנושאים
  • מדריכים
    • ריאקט
    • טייפסקריפט
    • ECMAScript 6
    • ES20XX
    • Node.js
    • Express
    • רספברי פיי
    • Babel
    • docker
    • MongoDB
    • Git
    • לימוד MySQL
    • SASS
    • jQuery
    • CSS3
    • HTML 5
    • SVN
    • LESS
  • פיתוח אינטרנט
    • פתרונות ומאמרים על פיתוח אינטרנט
    • jQuery Scripts
    • jQuery למתקדמים
    • יסודות בתכנות
    • נגישות אינטרנט
  • חדשות אינטרנט
  • מידע כללי על אינטרנט
    • רשת האינטרנט
    • בניית אתרי אינטרנט
  • rss logo

    לכל המאמרים

    לכל המאמרים שפורסמו באינטרנט ישראל משנת 2008 ועד עכשיו.
  • rss logo

    RSS Feed

    משתמשים בקורא RSS? אם כן, עקבו אחרי אינטרנט ישראל באמצעות פיד ה-RSS!
    מה זה RSS?
  • Twitter logo

    עקבו אחרי בטוויטר

    בחשבון הטוויטר שלי אני מפרסם עדכונים מהירים על חדשות בתחום התכנות והיזמות, התרעות על מצבי חירום ורכילות בוערת על תחום הווב.
    מה זה טוויטר?
  • facebook like image

    ערוץ הטלגרם של אינטרנט ישראל

    בערוץ הטלגרם של אינטרנט ישראל אני מפרסם את הפוסטים של באתר וכן עדכונים טכנולוגיים נוספים.
    מה זה טלגרם?
  • github logo

    הפרויקטים שלי בגיטהאב

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

כל הזכויות שמורות לרן בר-זיק ולאינטרנט ישראל | מדיניות הפרטיות של אתר אינטרנט ישראל | אתר אינטרנט ישראל נגיש לפי תקן WCAG 2.0 AA | הצהרת הנגישות של האתר | אבטחת מידע ודיווח על בעיית אבטחת מידע

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