דילוג לתוכן
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום
כיווץ
תחומים

תחומים - פורום חרדי מקצועי

💡 רוצה לזכור קריאת שמע בזמן? לחץ כאן!
  1. דף הבית
  2. תכנות
  3. הרצת callback רק עם התוצאה של הקריאה האחרונה

הרצת callback רק עם התוצאה של הקריאה האחרונה

מתוזמן נעוץ נעול הועבר תכנות
8 פוסטים 3 כותבים 323 צפיות
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • yossizY מנותק
    yossizY מנותק
    yossiz
    כתב ב נערך לאחרונה על ידי yossiz
    #1

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

    כתבתי פונקציה כזו:

    // wraps a function so that only the last call returns a value, all previous calls return null
    function returnOnce (func) {
      let callCounter = 0;
      const wrapper = async (...args) => {
        const myId = ++callCounter;
        const result = await func(...args);
        if (myId < callCounter) {
          return null;
        }
        return result;
      };
      return wrapper;
    }
    

    ואז:

    const doStuffReturnOnce = returnOnce(doStuff)
    function onKeyPress(key) {
      const result = await doStuffReturnOnce(key);
      if (result) {
        updateUI(result)
      }
    }
    

    אני מרגיש שיש דרך יותר טובה לעשות את זה.
    רעיונות מישהו?

    📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

    dovidD רפאלר 2 תגובות תגובה אחרונה
    3
    • dovidD מנותק
      dovidD מנותק
      dovid ניהול
      השיב לyossiz ב נערך לאחרונה על ידי dovid
      #2

      לפו"ר

      function returnOnce(func) {
          let last = null;
          return async function () {
              let curr = () => func(...args);
              let result = null;
              do {
                  last = curr;
                  result = await last();
              } while (last != curr)
              return result;
          };
      }
      

      מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

      בכל נושא אפשר ליצור קשר dovid@tchumim.com

      yossizY תגובה 1 תגובה אחרונה
      5
      • רפאלר מנותק
        רפאלר מנותק
        רפאל
        השיב לyossiz ב נערך לאחרונה על ידי רפאל
        #3

        ביכולתך לממש Debouncing כך:

        function returnOnce(func) {
            let counter = 0;
            return async (...args) => {
                const id = ++counter;
                await new Promise(x => setTimeout(x, 300));
                if (counter > id) return;
                const result = await func(...args);
                if (counter === id) {
                    return result
                }
            };
        }
        

        Reactive programming

        אישית הייתי משתמש בRxJs עבור המשימה, הרבה יותר אפשרויות, פחות קוד לתחזוק,

        fromEvent(input, 'keyup')
            .pipe(
                debounceTime(300),
                distinctUntilChanged(),
                switchMap(e => func(e.target.value))
            )
            .subscribe(result => updateUi(result))
        

        בדוגמא למעלה אנו יוצרים Observable שמאזין לאירוע keyup של התבת טקסט,
        לאחר מכן אנחנו מוסיפים אופרטורים (באמצעותם ניתן לקבוע מה יתרחש בשעה שערך יוחזר) באמצעות המתודה Pipe:

        1. DebounceTime
          עבור כל ערך שחוזר, המתן X מילי שניות, במידה ובמהלך הזמן הזה ערך חדש מופיע, התעלם מהערך הנוכחי, וחזור על התהליך שוב, במידה והזמן חלף ללא הופעת ערך חדש, העבר את הערך לאופרטור הבא.

        2. DistinctUntilChanged
          התעלם מהערך הנוכחי במידה והוא זהה לערך הקודם, במידה ולא, העבר את הערך לאופרטור הבא.

        3. SwitchMap
          האופרטור מקבל מתודה שמקבלת את הערך שחזר מהאופרטור הקודם כפרמטר ומחזירה Observable/Promise, המתודה תרוץ עבור כל ערך שחוזר, הObservable/Promise הפנימיים יתבטלו במידה והם עדיין רצים בשעה שערך חדש מופיע (עבור Promise אין לדבר משמעות מלבד התעלמות מהתוצאה).

        Promise vs Observable

        1. Observable אינו מוגבל להחזרת ערך בודד.
        2. Promise רץ ברגע שהוא נוצר, לעומת Observable שירוץ רק במידה ונרשם אליו באמצעות Subscribe (הדבר אינו נכון עבור Hot Observable אולם השימוש בו נדיר יותר ונתעלם ממנו לצורך העניין).

        לסיכום

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

        yossizY תגובה 1 תגובה אחרונה
        6
        • yossizY מנותק
          yossizY מנותק
          yossiz
          השיב לdovid ב נערך לאחרונה על ידי
          #4

          @dovid נראה לי שיש בעייתיות בקוד שלך כי יוצא הרבה קריאות מיותרות. כי כל פעם שהפונקציה "נעקפת" (דהיינו שמישהו אחר נכנס לפונקציה לפני שיצאת משם) אתה קורא שוב לפונקציה האחרונה בתור.

          📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

          תגובה 1 תגובה אחרונה
          3
          • yossizY מנותק
            yossizY מנותק
            yossiz
            השיב לרפאל ב נערך לאחרונה על ידי
            #5

            @רפאל
            א) תודה רבה על התשובה מאירת העיניים. עדיין נשאר לי הרבה שיעורי בית עד שאלמד טוב את הספרייה, אבל זה בהחלט מרחיב את הדעת.
            ב) עשיתי crash course מהיר על rxjs, ולפי מיעוט הבנתי לבינתיים, הקוד שהבאת לא עושה בדיוק מה שביקשתי. אני רוצה לקבל את התוצאה של הקריאה האחרונה. לא התוצאה שחזרה אחרונה.

            📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

            רפאלר תגובה 1 תגובה אחרונה
            2
            • רפאלר מנותק
              רפאלר מנותק
              רפאל
              השיב לyossiz ב נערך לאחרונה על ידי
              #6

              @yossiz אמר בהרצת callback רק עם התוצאה של הקריאה האחרונה:

              אני רוצה לקבל את התוצאה של הקריאה האחרונה. לא התוצאה שחזרה אחרונה.

              אני ממליץ לך לקרוא על SwitchMap.

              yossizY תגובה 1 תגובה אחרונה
              2
              • yossizY מנותק
                yossizY מנותק
                yossiz
                השיב לרפאל ב נערך לאחרונה על ידי yossiz
                #7

                @רפאל נעלבתי... (רק טיפה 😉 ) נראה לך שהערתי בלי לקרוא את התיעוד? אני מבין שטעיתי, ורק עכשיו אני מתחיל להבין איפה הטעות שלי.
                אני הבנתי שה-map מחזיר observable (פנימי) חדש בצורה אסינכרונית אחרי שהקריאה לשרת חוזרת. עכשיו אני מבין שפרומיס יכול להיות במקום observable והוא מחזיר מיד את הפרומיס בצורה סינכרונית. זה נכון?

                📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

                רפאלר תגובה 1 תגובה אחרונה
                3
                • רפאלר מנותק
                  רפאלר מנותק
                  רפאל
                  השיב לyossiz ב נערך לאחרונה על ידי רפאל
                  #8

                  @yossiz אמר בהרצת callback רק עם התוצאה של הקריאה האחרונה:

                  נעלבתי

                  גם לי לא לקח יום אחד להבין איך הכל עובד, ואני בטוח שלך יקח פחות.

                  @yossiz אמר בהרצת callback רק עם התוצאה של הקריאה האחרונה:

                  והוא מחזיר מיד את הפרומיס בצורה סינכרונית

                  בהחלט, אבל שים לב להבדלים בין:

                  • Map מיועד למיפוי ערך פשוט
                  • SwitchMap יבטל את הרישום לObservable הפנימי הקיים וייצור Observable עבור הערך החדש
                  • MergeMap ייצר Observable פנימי עבור הערך החדש, בלי לבטל את הObservable הפנימי, כך שאין סוף Observables פנימיים יכולים להיות פעילים במקביל (אפשר להגביל את הכמות).
                  • ExhaustMap יתעלם מערכים חדשים כל עוד שהObservable הפנימי פעיל.
                  • ConcatMap ימתין שהObservable הפנימי יושלם לפני שיצור Observable פנימי נוסף, הערכים נשמרים בBuffer פנימי.

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

                   
                   

                  תרשים ציר זמן המתאר את ההבדלים בין הMaps השונים:

                  • $Source מתאר את הstream המקורי.
                    הכחול מייצג את הערך הראשון מהstream החיצוני
                    הצהוב את השני
                    הירוק את השלישי
                  • $Target מייצג את הstream הפנימי (כל איבר מהstream החיצוני ימופה לstream פנימי)

                  באיור הבא כל איבר בstream המקורי "משתכפל" כמספר הערכים שהstream הפנימי פלט (בכפוף למדיניות של האופרטורים הנ"ל):
                   
                  כיתוב בבעיות טעינה

                  תגובה 1 תגובה אחרונה
                  5

                  בא תתחבר לדף היומי!
                  • התחברות

                  • אין לך חשבון עדיין? הרשמה

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