פונקציות גנרטור בג'אווהסקריפט

פונקציות גנרטור בג'אווהסקריפט

במאמר זה נסביר על פונקציות גנרטור בג'אווהסקריפט.

YouTube Video

פונקציות גנרטור בג'אווהסקריפט

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

מהן פונקציות גנרטור?

פונקציית גנרטור מוגדרת באמצעות function* (הגדרת פונקציה עם כוכבית) ובניגוד לפונקציות רגילות, היא יכולה להפסיק את ביצועה באמצע ולהמשיך תוך שמירה על מצבה. פונקציות גנרטור מאפשרות "הרצה עצלה" ומחזירות תוצאות באופן הדרגתי, מה שמאפשר ניהול זיכרון יעיל ועיבוד סדרתי.

תחביר

1function* generatorFunction() {
2    yield 'First value';
3    yield 'Second value';
4    return 'Done';
5}

באופן זה, פונקציית גנרטור יכולה להכיל מספר ביטויי yield ולהשתמש ב-yield כדי להשהות את ביצועה. כשפונקציית גנרטור נקראת, גוף הפונקציה לא מבוצע מיד ומוחזר אובייקט גנרטור. ניתן לקרוא לשיטת next() על אובייקט זה כדי להמשיך את הפונקציה מהנקודה שבה הופסקה.

שימוש בסיסי בפונקציות גנרטור

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

 1function* simpleGenerator() {
 2    yield 1;
 3    yield 2;
 4    yield 3;
 5}
 6
 7const gen = simpleGenerator();
 8
 9console.log(gen.next()); // { value: 1, done: false }
10console.log(gen.next()); // { value: 2, done: false }
11console.log(gen.next()); // { value: 3, done: false }
12console.log(gen.next()); // { value: undefined, done: true }

נקודה חשובה לזכור היא שהגנרטור מחזיר ערכים בכל פעם עם yield, וכאשר המאפיין done הוא false, זה מצביע על כך שיש עוד ערכים שיגיעו. הקריאה האחרונה ל-next() מחזירה done: true, מה שמעיד שהגנרטור סיים.

מילת המפתח yield והשהיית ערכים

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

 1function* generatorWithYield() {
 2    const value1 = yield 'First yield';
 3    console.log('Received value:', value1);
 4    const value2 = yield 'Second yield';
 5    console.log('Received value:', value2);
 6}
 7
 8const gen = generatorWithYield();
 9
10console.log(gen.next());        // { value: 'First yield', done: false }
11console.log(gen.next('Apple')); // Received value: Apple
12                                // { value: 'Second yield', done: false }
13console.log(gen.next('Banana'));// Received value: Banana
14                                // { value: undefined, done: true }

בדוגמה זו, הקריאה next('Apple') שולחת את הערך 'Apple' לפונקציית הגנרטור, שם הוא משמש בתוך הפונקציה.

ניהול מצב הגנרטור

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

 1function* infiniteGenerator() {
 2    let i = 0;
 3    while (true) {
 4        yield i++;
 5        if (i > 10) {
 6            break;
 7        }
 8    }
 9}
10
11const gen = infiniteGenerator();
12
13console.log(gen.next().value); // 0
14console.log(gen.next().value); // 1
15console.log(gen.next().value); // 2
16// Continues...

הגנרטור הזה מייצר מספרים ברצף תוך שימוש בלולאת while(true), ומאפשר לך לקבל ערכים לפי הצורך. זה מאפשר עיבוד יעיל של סטי נתונים גדולים.

יישומים של פונקציות גנרטור

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

1function* apiRequestGenerator() {
2    yield fetch('https://codesparklab.com/json/example1.json');
3    yield fetch('https://codesparklab.com/json/example2.json');
4    yield fetch('https://codesparklab.com/json/example3.json');
5}

לכן, גנרטורים, שניתן להשתמש בהם לעיבוד אסינכרוני, מועילים מאוד לטיפול יעיל בנתונים באופן סדרתי.

גנרטורים אסינכרוניים

גנרטורים אסינכרוניים שהוצגו ב-ES2018 מאפשרים לך להחזיר ערכים אסינכרוניים בצורה סדרתית על ידי שילוב של async ו-yield. זה מאפשר לך לכתוב עיבוד אסינכרוני בצורה תמציתית יחד עם await.

תחביר

 1async function* asyncGenerator() {
 2    yield await Promise.resolve(1);
 3    yield await Promise.resolve(2);
 4    yield await Promise.resolve(3);
 5}
 6
 7const gen = asyncGenerator();
 8
 9(async () => {
10    for await (const value of gen) {
11        console.log(value); // 1, 2, 3
12    }
13})();

גנרטורים אסינכרוניים יכולים לשלוף ערכים בצורה סדרתית באמצעות לולאת for await...of. התבנית הזו מועילה במיוחד כאשר מטפלים בזרמי נתונים אסינכרוניים.

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

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

 1function* asyncFlow() {
 2    const data1 = yield fetch('https://codesparklab.com/json/example1.json');
 3    console.log(data1);
 4    const data2 = yield fetch('https://codesparklab.com/json/example2.json');
 5    console.log(data2);
 6}
 7
 8const gen = asyncFlow();
 9
10function handleAsync(generator) {
11    const next = (promise) => {
12        promise.then((result) => {
13        const { value, done } = generator.next(result);
14        if (!done) {
15            next(value);
16        }
17        });
18    };
19
20    next(generator.next().value);
21}
22
23handleAsync(gen);

הקוד הזה מבצע בקשות API בצורה סדרתית באמצעות גנרטור ומעבד את התוצאות.

סיכום

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

תוכלו לעקוב אחר המאמר שלמעלה באמצעות Visual Studio Code בערוץ היוטיוב שלנו. נא לבדוק גם את ערוץ היוטיוב.

YouTube Video