פונקציות גנרטור ב-TypeScript
מאמר זה מסביר את פונקציות הגנרטור ב-TypeScript.
ניתן ללמוד הכל מהבסיס לגבי אופן השימוש בפונקציות גנרטור ועד דוגמאות מתקדמות שמשולבות עם עיבוד אסינכרוני, יחד עם דוגמאות קוד.
YouTube Video
פונקציות גנרטור
פונקציות גנרטור ב-TypeScript מספקות פונקציונליות דומה לפונקציות הגנרטור של JavaScript. פונקציות גנרטור מוגדרות באמצעות function* (הצהרת פונקציה עם כוכבית) והן פונקציות מיוחדות שיכולות להשהות ולהמשיך בביצוע שלא כמו פונקציות רגילות.
כאשר קוראים לפונקציית גנרטור, מוחזר איטרטור שמייצר ערכים אחד אחד באמצעות איטרטור זה, וניתן להשהות את הביצוע באמצעות מילת המפתח yield או לשלוח ערכים מבחוץ.
תחביר בסיסי של פונקציות גנרטור
1function* myGenerator(): Generator<number, void, unknown> {
2 yield 1;
3 yield 2;
4 yield 3;
5}
6
7const gen = myGenerator();
8
9console.log(gen.next().value); // 1
10console.log(gen.next().value); // 2
11console.log(gen.next().value); // 3
12console.log(gen.next().done); // true (Iteration finished)
- הגדר פונקציית גנרטור באמצעות
function* myGenerator(). - מילת המפתח
yieldמשהה את ביצוע הפונקציה ומחזירה ערך. - בכל פעם שמזמינים את המתודה
next(), הביצוע של פונקציית הגנרטור ממשיך ומתקדם עד ל-yieldהבא.
next() מחזיר אובייקט המכיל את הערך הבא ואת המאפיין done. כאשר done הוא true, הדבר מסמן שכל הערכים נוצרו ועיבוד הגנרטור הושלם.
שימושים בפונקציות גנרטור
שימוש בפונקציות גנרטור מאפשר ייצוג קל של עיבוד סדרתי. בדוגמה הבאה, אנו יוצרים פונקציית גנרטור שמייצרת רצף מספרים.
1function* sequenceGenerator(start: number = 0, step: number = 1) {
2 let current = start;
3 while (true) {
4 yield current;
5 current += step;
6 }
7}
8
9const seq = sequenceGenerator(1, 2);
10
11console.log(seq.next().value); // 1
12console.log(seq.next().value); // 3
13console.log(seq.next().value); // 5
- בדוגמה זו,
sequenceGeneratorמייצר רצף מספרים שממשיך עד אינסוף. השתמש ב-yieldכדי להחזיר ערכים בכל שלב, ולייצר את הערך הבא בקריאות הבאות.
העברת ערכים ל-next
המתודה next() יכולה לקבל ערך שניתן לשלוח לפונקציית הגנרטור.
1function* adder() {
2 const num1 = yield;
3 const num2 = yield;
4 yield num1 + num2;
5}
6
7const addGen = adder();
8addGen.next(); // Initialization
9addGen.next(5); // Set 5 to num1
10const result = addGen.next(10).value; // Set 10 to num2 and get result
11console.log(result); // 15
- בדוגמה זו,
next(5)ו-next(10)שולחים את הערכים שלהם לפונקציית הגנרטור, ו-yield num1 + num2מחזיר את סכומם.
return ו-throw
return(value)יכול לסיים את הגנרטור ולהחזיר את הערך שצוין.throw(error)יכול לזרוק חריג בתוך הגנרטור, ומשמש לטיפול בחריגים בתוך הגנרטור.
1function* testGenerator() {
2 try {
3 yield 1;
4 yield 2;
5 } catch (e) {
6 console.error("Error caught:", e);
7 }
8}
9
10const gen = testGenerator();
11console.log(gen.next().value); // 1
12gen.throw(new Error("An error occurred!")); // Error caught: An error occurred!
- בדוגמה זו, המתודה
throwמשמשת ליצירת שגיאה בתוך הגנרטור, ושגיאה זו נלכדת בתוך הגנרטור.
הגדרת סוג ב-TypeScript
ניתן להגדיר את סוג הפונקציה של מחולל (generator) בפורמט הבא.
1// Generator<YieldType, ReturnType, NextType>
2function* myGenerator(): Generator<number, void, unknown> {
3 yield 1;
4 yield 2;
5 yield 3;
6}- יש להגדיר את הסוגים בצורה של
Generator<YieldType, ReturnType, NextType>.YieldTypeהוא סוג הערך שמוחזר על ידיyield.ReturnTypeהוא סוג הערך שמוחזר על ידיreturn.NextTypeהוא סוג הערך שמועבר ל־next().
בדוגמה הבאה, סוגים ספציפיים מוגדרים לשימוש בטוח בגנרטור עם סוגים.
1function* numberGenerator(): Generator<number, void, number> {
2 const num1 = yield 1;
3 const num2 = yield num1 + 2;
4 yield num2 + 3;
5}
6
7const gen = numberGenerator();
8
9console.log(gen.next().value); // 1
10console.log(gen.next(10).value); // 12 (10 + 2)
11console.log(gen.next(20).value); // 23 (20 + 3)
גנרטורים ועיבוד אסינכרוני
ניתן להשתמש בגנרטורים גם לעיבוד אסינכרוני. לדוגמה, ניתן להשתמש ב-yield להמתנה לתוצאות של פעולות אסינכרוניות תוך המשך עיבוד לפי סדר. עם זאת, ב-TypeScript או JavaScript, משתמשים בדרך כלל ב-async/await.
1function* asyncTask() {
2 const result1 = yield fetch("https://codesparklab.com/json/example1.json");
3 console.log(result1);
4
5 const result2 = yield fetch("https://codesparklab.com/json/example2.json");
6 console.log(result2);
7}לכן, למרות שניתן לעבד פעולות אסינכרוניות לפי סדר עם גנרטורים, הם אינם בשימוש נפוץ עבור עיבוד אסינכרוני מאחר ש-Promises ו-async/await נוחים יותר.
סיכום
- פונקציות גנרטור הן פונקציות מיוחדות המוגדרות עם
function*שיכולות להחזיר ערכים עםyieldתוך עצירת ביצוע הפונקציה. - יש להשתמש ב-
next()כדי להמשיך את הגנרטור ולקבל ערכים. בנוסף, ניתן לשלוח ערכים לגנרטור על ידי שימוש ב-next(value). - ניתן להשתמש ב-
return()וב-throw()כדי לסיים פונקציות גנרטור או לטפל בשגיאות. - כאשר משתמשים בגנרטורים ב-TypeScript, ניתן להשתמש בהגדרות סוג כדי לכתוב קוד בטוח סוג.
גנרטורים הם כלים חזקים המאפשרים לך לשלוט באופן גמיש בתהליך האיטרציה.
תוכלו לעקוב אחר המאמר שלמעלה באמצעות Visual Studio Code בערוץ היוטיוב שלנו. נא לבדוק גם את ערוץ היוטיוב.