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

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

כאשר אנו מגדירים את הטיימר, הפרמטר השני הוא העיכוב . אם לא נציין דבר, ערך ברירת המחדל הוא 0. אבל הנה החלק המעניין: מה אם הפונקציה שלנו זקוקה לנתונים חיצוניים? ישנן שתי דרכים עיקריות לטפל בכך. הראשונה היא באמצעות פונקציה אנונימית שעוטפת את הקריאה המקורית, ומאפשרת לנו להעביר כל ארגומנט שנרצה. הדרך השנייה, והאלגנטית יותר, היא לנצל את העובדה ש-`setTimeout` מאפשר לנו להוסיף ארגומנטים נוספים החל מהפרמטר השלישי, אשר ממופים ישירות לפונקציית הקריאה החוזרת.
ניהול ביטולים עם clearTimeout

לפעמים החיים לוקחים תפניות בלתי צפויות, ואנחנו צריכים לבטל משימה מתוזמנת שעדיין לא בוצעה. לשם כך, עלינו לדעת ש-`setTimeout` מחזירה מזהה ייחודי (a `timerId`). בדפדפנים, מזהה זה הוא בדרך כלל מספר, בעוד שב-Node.js זהו אובייקט מורכב יותר. אם נאחסן ערך זה במשתנה, נוכל לקרוא לפונקציה ` clearTimeout(timerId)` כדי לבטל את הפעולה ולמנוע את ביצוע הקוד, ובכך לחסוך במשאבי מערכת.
השוואה: setTimeout לעומת setInterval

נפוץ מאוד לבלבל בין שתי השיטות הללו. בעוד ש-`setTimeout` מבצע את הפונקציה פעם אחת בלבד, `setInterval` מבצע אותה שוב ושוב בכל פעם שחולף המרווח המוגדר. עם זאת, יש טריק מתקדם: `setTimeout` מקונן . זה כרוך בקריאה ל-`setTimeout` חדש ממש בסוף ביצוע הפונקציה הנוכחית.
טכניקה זו גמישה הרבה יותר מ-`setInterval` מכיוון שהיא מבטיחה עיכוב אמיתי וקבוע בין סוף משימה אחת לתחילתה של הבאה. עם `setInterval`, אם הפונקציה אורכת זמן רב יותר לביצוע מזמן המרווח, קריאות יכולות להצטבר או לפעול ללא השהייה. לעומת זאת, קינון מאפשר לך להתאים את הזמן באופן דינמי, וזה חיוני אם, למשל, אתה מבצע בקשות לשרת שעשוי להיות עמוס יתר על המידה ואתה צריך להגדיל את מרווח ההמתנה.
המקרה המוזר של אפס עיכוב ומגבלות
אם תשתמשו בפונקציה `setTimeout(func, 0)` , אולי תחשבו שהפונקציה מופעלת באופן מיידי, אבל זה לא המקרה. מה שקורה הוא שהמתזמן שם את המשימה בתור להפעלה בהקדם האפשרי , אבל תמיד לאחר שהסקריפט הנוכחי הסתיים לחלוטין. זוהי דרך לומר, "סיימו את מה שאתם עושים, וברגע שתוכלו, עשו זאת".
יתר על כן, חשוב לציין שדפדפנים מטילים מגבלה מינימלית של 4 מילישניות עבור טיימרים מקוננים לאחר שהם פועלים חמש פעמים ברציפות. זהו שריד מגרסאות קודמות כדי למנוע קריסה של הדפדפן. עם זאת, הדיוק אינו מדויק; אם המעבד עמוס יתר על המידה או שהכרטיסייה פועלת ברקע , הדפדפן עשוי לעכב את הביצוע עד 300 מילישניות או אפילו שנייה שלמה כדי לחסוך בסוללה.
יישום במסגרות מודרניות
שיטה זו מתורגמת בצורה מושלמת לכלים כמו React או Angular. ב- React , הגישה האידיאלית היא לעטוף את `setTimeout` בתוך hook מסוג `useEffect` כדי לשלוט במחזור החיים של הרכיב ולהבטיח שהטיימר מנוקה באמצעות פונקציית return, ובכך למנוע דליפות זיכרון. ב- Angular , ניתן לשלב אותה בקלות בבנאי הרכיב או ב-hooks של מחזור החיים כדי להפעיל התראות או לטעון נתונים אסינכרוניים.
עבור אלו המחפשים רמות מורכבות גבוהות יותר, ניתן לשלב טיימרים עם Promises ו-async/await . זה מאפשר יצירת רצפי המתנה קריאים ומקצועיים הרבה יותר, תוך הימנעות מ"גיהנום הקריאה החוזרת" הידוע לשמצה ומאפשר ניהול של טיימרים מרובים באופן אסינכרוני ובצורה מסודרת.
היכולת לנהל זמן ב-JavaScript היא בסיסית ליצירת ממשקים דינמיים, החל משעונים דיגיטליים ואנימציות ועד למערכות של ניסיונות חוזרים של חיבורים. שליטה ב-`setTimeout`, החלפתו ב-`clearTimeout` והבנת האופן שבו הוא מתקשר עם לולאת האירועים מאפשרת לך לייעל את ביצועי האפליקציה ולשפר את חוויית המשתמש הסופי, תוך התחשבות תמיד בכך שדיוק הזמן תלוי במידה רבה בסביבה ובעומס המערכת.