קוד חמוד/רע/איום ליצירת רשימת מספרים ב-JS
-
אגב איטרטורים יכולים ועשויים להיות אינסופיים וזה לא באג,
האופרטור [...] מסוכן מבחינת זה, ואין בJS נכון להיום מתודה מקוצרת לקחת רק חלק מוגבל מהייצור של הפונקציה.
באופן כללי JS עדיין בכלל לא מנצלת את הכח של האיטרטורים כל עוד לא מממשים את זה:
https://github.com/tc39/proposal-iterator-helpers שזה אוסף פונקציות לעבודה על אוספים, שהעבודה נעשית תוך כדי משיכת האוסף (כמו בfor of). -
פייתון הרבה יותר מפותח בפן הזה ויש להם פונקציה לזה:
range
.
https://docs.python.org/3/library/stdtypes.html#range
מימוש JS-י ייראה ככה:function* range (start, stop, step = 1) { if (arguments.length < 1) { throw new TypeError('At least one argument is required') } for (const arg of [...arguments]) { if (!Number.isInteger(arg)) { throw new TypeError('All arguments must be integers'); } } if (step === 0) { throw new TypeError('Step cannot be zero'); } if (arguments.length === 1) { stop = start; start = 0; } let i = start; while (step > 0 && i < stop || step < 0 && i > stop) { yield i; i += step; }; }
ניסיתי לכתוב אותה בצורה הרמטית, אשמח לתיקונים
שימוש:
for (const i of range(10)) console.log(i); // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 for (const i of range(1, 11)) console.log(i); // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 for (const i of range(0, 30, 5)) console.log(i); // 0, 5, 10, 15, 20, 25 for (const i of range(0, -10, -1)) console.log(i); // 0, -1, -2, -3, -4, -5, -6, -7, -8, -9
וכן הלאה
אגב, נראה לי שרוב ככל הפעמים שאנשים מחפשים איך למלאות מערך עם מספרים זו טעות. במקום זה הם צריכים לולאתfor...of
על iterator. -
@dovid זו נקודה מאוד מעניינת. בשביל לבדוק את זה ניסיתי להריץ בקונסול לולאה אינסופית פשוטה:
let a = 0; while (true) { b+=1; }
כמובן שהטאב נתקע ולא הגיב ללחיצות וכו'. אבל עדיין הוא לא קרס.
אח"כ ניסיתי להריץ עוד לולאה אינסופית פשוטה, שמכניסה למערך את אותו מספר, והטאב קרס ממש מיד.let a = []; let b = 0; while (true) { a.push(b++); }
ואנוכי הקטן לא מצליח להבין מה ההיגיון בעניין הזה.. ניסיתי לחפש אינפורמציה על לולאות אינסופיות ב-JS, לא כ"כ מצאתי. בכל מקרה זו נקודה מעניינת.
-
@מוטי-אורן ההבדל הוא שבדוגמה הראשונה אתה לוקח רק מעבד, מעבד יש בשפע. בגלל שלטאב מקוצה רק חוט אחד, הוא לא מגיחב, אבל המחשב מבצע את זה מהר מאוד והוא אפילו לא מתחיל להזיע.
ובדוגמה של [...] וגם של הpush אתה לוקח המממממון זיכרון. יש הגבלה לזיכרון שטאב יכול לקחת, ובעת שהוא עובר את המגבלה הוא מוצא להורג. -
@dovid זכור לי שראיתי כמה פעמים דברים כאלו בספריות טובות, אולי זה עדיין פחות נפוץ.
ראיתי שיש פונקציית range ב-lodash (כצפוי...) אבל זה מחזיר מערך ולא iterable.
אצלם גם אם תביא רק ארגומנט אחד הוא מייצג את ה-end.
ניסיתי להשוות את הקוד שלהם לקוד שלי. אצלם הקוד קצת יותר מסובך בעיקר כי הם מאוד גמישים בצורת הארגומנטים. -
עד כמה שIterators/Generators שימושיים, סבורני שהגירסה האסינכרונית (AsyncIterator) משמעותית לעין ערוך.
להלן מימוש של Polling באמצעות Async Generator:class StockPricePoller { private readonly _url = "https://www.random.org/integers/?num=1&min=1&max=6&col=1&base=10&format=plain&rnd=new"; public async waitFor(thresholdPrice: number): Promise<number> { for await (const currentPrice of this.stockPrice()) if (currentPrice >= thresholdPrice) return currentPrice; } private async *stockPrice(): AsyncGenerator<number> { while (true) yield await fetch(this._url).then(x => +x.text()) } }
שימוש:
const price = await new StockPricePoller().waitFor(5);
הדוגמא לא מושלמת, והיה רצוי להמתין בין הבקשות (Throttling).
אגב הרעיון קיים גם ב#C ומכונה AsyncEnumerable
בקוטלין הוא מכונה Asynchronous Flow (דגם היברידי של תכנות אסינכרוני ותכנות ריאקטיבי). -
@dovid הנה משהו מישראלי: https://github.com/DanShappir/Seq
פעם שמעתי אותו מדבר על הנושא בפודקאסט.
לא יודע כמה יציב הספרייה. הפודקאסט היה ממש טוב (פעם היה פתוח בנטפרי, נראה לי שהם שינו את הדומיין שלהם)
בלוג שלו בנושא
(אני מקווה שהרמה הכללית של הביצועים ב-WIX לא משקפים את הרמה שלו....) -
@רפאל מי נתן לך רשות להכניס לפה typescript?
(אגב, אני מניח שאתה מתכוון ל-polling ולא ל-pulling).
@רפאל אמר בקוד חמוד/רע/איום ליצירת רשימת מספרים ב-JS:
שהגירסה האסינכרונית (AsyncIterator) משמעותית לעין ערוך
גם אני השתמשתי בדבר כזה לאחרונה. זה נותן הרגשה טובה
אבל אני לא מבין למה אתה אומר שזה משמעותית לאין ערוך. זה הרחבה של אותו רעיון לתחום האסינכרוני. תמיד היה אפשר לממש את זה עם לופ אחר. -
מי נתן לך רשות להכניס לפה typescript?
אני מתנצל, לא העלתי בדעתי שהפורום הוא TypeFree.
אני מניח שאתה מתכוון ל-polling ולא ל-pulling
צודק תיקנתי, (בראש שלי זה תמיד Pulling, מלשון משיכה, ולא סקר).
אבל אני לא מבין למה אתה אומר שזה משמעותית לאין ערוך
אכן מימוש של רעיון זהה, אולם תבדוק מתי מימשת Iterator או לחלופין יצרת Generator שאינו אסינכרוני לאחרונה.
Enumrable/Enumerator אכן שימושיים ב#C, בשילוב עם מתודות הLINQ, אולם אינם שימושיים כלל כשלעצמם, לכן לדעתי כל עוד שהIterator Helpers אינם קיימים בJS, אין הרבה מה לעשות עם הIterators/Generators הללו.
-
@dovid אמר בקוד חמוד/רע/איום ליצירת רשימת מספרים ב-JS:
@yossiz למיטב זכרוני במנטליות של JS לא מקובל לשנות משמעות ארגומנט במיקום מסויים כאשר הועברו מס' שונה של ארגומנטים.
במילים אחרות בJS הפונקציה תמיד תהיה חייבת לקבל שני ארגומנטים.זה לא מדוייק. ואחת הדוגמאות הכי בולטות והכי מעצבנות עבורי - זה הAPI של הקנבס.
-
@davidnead הפרמטר השני הוא תמיד ההמיקום מהנקודה השמאלית העליונה. יש כמובן הבדלים באופן ההבנה והטיפול של הפרמטר אבל עדיין שייך לקרוא לו שם ולזהות את משמעותו הכללית.
אני התכוונתי לכזה דבר:void log(message); void log(color, message);
זה לענ"ד נגד מנטליות הפיתוח הנפוצה בJS, יש לזה גם משמעות לשמות הפרמטרים בפונקציה המקבלת.
בשפות שיש תמיכה בoverloding אז פונקציה נפרדת לגמרי לטיפול בכל צורה, וממילא השמות יכולים להשתנות, אבל בJS פונקציה אחת מטפלת אז היא תתמודד עם מערך של arguments או שמות כמו p1, p2 ותסיק את משמעותם (ולא רק את דרך הטיפול), שזה קוד מאוד לא נחמד לעבודה. -
@dovid אמר בקוד חמוד/רע/איום ליצירת רשימת מספרים ב-JS:
@davidnead הפרמטר השני הוא תמיד ההמיקום מהנקודה השמאלית העליונה
לא מבין למה אתה אומר את זה. זה מיקום של המקור וזה מיקום של היעד. צווי דינים מבלבלים. במקרה השלישי למשל, הפרמטר השני הוא הנקודה השמאלית העליונה בתוך תמונת המקור, בעוד בשני המקרים הראשונים זו הנקודה השמאלית העליונה בקנבס.
אם תכתוב
ctx.drawImage(src, 50,50)
התמונה תצוייר החל מהפינה השמאלית העליונה שלה, אל תוך הקנבס - החל מ50 פיקסלים למטה וימינה מהפינה השמאלית העליונה שלו.
אבל אם תכתובctx.drawImage(src, 50, 50, 100, 100, 0, 0, 100, 100)
אתה חותך את התמונה, והיא תצויר החל מ50 פיקסלים למטה וימינה מהפינה השמאלית העליונה שלה, אל תוך בקנבס החל מהפינה השמאלית העליונה שלו.
בחרתי דוקא את הדוגמה הזו, כי אותה אני זוכר במיוחד כי היא מעצבנת בגלל שהמשמעות נשמעת דומה, אך בפועל היא אחרת לגמרי. זה מבלבל.