المؤقتات في JavaScript: setTimeout و setInterval
رسالة «تم الحفظ» تظهر ثم تختفي بعد ثلاث ثوانٍ. ساعة رقمية تتحدث كل ثانية. عدّ تنازلي لنهاية العرض. شريط صور ينتقل تلقائياً. كل هذه تحتاج أن تقول للمتصفح: «نفّذ هذا لاحقاً» أو «نفّذه كل فترة». في هذا الدرس ستتعلم دالتين لذلك، وستفهم معهما أول أسرار JavaScript: كيف تتعامل مع الوقت.
setTimeout: نفّذ بعد مدة
Section titled “setTimeout: نفّذ بعد مدة”console.log("بدأ البرنامج");
setTimeout(() => { console.log("مرّت ثانية");}, 1000);بدأ البرنامجمرّت ثانيةsetTimeout تأخذ معاملين:
- دالة تُنفَّذ لاحقاً.
- مدة الانتظار بالملّي ثانية. كل 1000 ملّي ثانية تساوي ثانية واحدة.
تخيّلها مثل منبّه الهاتف: تضبطه على وقت، وتكمل يومك، وعندما يحين الوقت يرنّ.
المفاجأة: الكود لا ينتظر
Section titled “المفاجأة: الكود لا ينتظر”ما ناتج هذا الكود؟ توقّعه قبل أن تقرأ الإجابة:
console.log("1");
setTimeout(() => { console.log("2");}, 500);
console.log("3");132الرقم 3 طُبع قبل 2! السبب أن setTimeout لا توقف البرنامج. هي تسجّل المنبّه فقط وتعود فوراً، فيكمل البرنامج إلى السطر التالي. وبعد نصف ثانية تُنفَّذ الدالة المؤجلة.
هذا السلوك يسمى غير متزامن (Asynchronous): الكود لا يُنفَّذ بترتيب كتابته. وهو أساس كل ما سيأتي: جلب البيانات من الإنترنت وانتظار المستخدم.
حتى مع صفر
Section titled “حتى مع صفر”setTimeout(() => { console.log("المؤجل");}, 0);
console.log("العادي");العاديالمؤجلحتى بمدة صفر تُنفَّذ الدالة المؤجلة بعد انتهاء الكود العادي كله. القاعدة: JavaScript تنهي ما بيدها أولاً، ثم تلتفت إلى ما في قائمة الانتظار.
تخيّل موظفاً واحداً على شباك: يخدم من أمامه حتى ينتهي، ثم ينادي التالي في الطابور. مهما كان التالي مستعجلاً، لن يقطع على من يُخدم الآن. JavaScript تعمل بنفس الطريقة: مهمة واحدة في كل لحظة.
إلغاء المؤقت: clearTimeout
Section titled “إلغاء المؤقت: clearTimeout”setTimeout تُرجع رقماً يعرّف المؤقت. احفظه إذا أردت الإلغاء لاحقاً:
const timerId = setTimeout(() => { console.log("لن أُطبع أبداً");}, 1000);
clearTimeout(timerId);console.log("أُلغي المؤقت");أُلغي المؤقتاستخدام شائع: رسالة تختفي بعد 5 ثوانٍ، لكن المستخدم أغلقها بيده قبل ذلك، فتلغي المؤقت حتى لا يحاول إخفاء رسالة غير موجودة.
setInterval: كرّر كل فترة
Section titled “setInterval: كرّر كل فترة”setTimeout تنفذ مرة واحدة. أما setInterval فتكرر التنفيذ كل فترة إلى أن توقفها:
let count = 0;
const intervalId = setInterval(() => { count++; console.log("نبضة", count);
if (count === 3) { clearInterval(intervalId); console.log("توقف"); }}, 200);نبضة 1نبضة 2نبضة 3توقفsetIntervalتُرجع رقماً تعريفياً مثلsetTimeout.clearIntervalتوقف التكرار. بدونها يستمر المؤقت إلى الأبد.
setTimeout |
setInterval |
|
|---|---|---|
| عدد مرات التنفيذ | مرة واحدة | يتكرر |
| الإيقاف | clearTimeout |
clearInterval |
| أمثلة | إخفاء رسالة، تأخير بحث | ساعة، عدّ تنازلي، عرض شرائح |
تمرير دالة جاهزة
Section titled “تمرير دالة جاهزة”يمكنك إعطاء المؤقت اسم دالة موجودة بدلاً من دالة سهمية:
function sayHello() { console.log("أهلاً!");}
setTimeout(sayHello, 300);أهلاً!نكتب sayHello بدون أقواس. لو كتبت setTimeout(sayHello(), 300) لنُفِّذت الدالة فوراً، وأُعطي المؤقت ناتجها بدلاً منها.
المشروع: عدّ تنازلي
Section titled “المشروع: عدّ تنازلي”الناتج
اضغط «ابدأ» وراقب الرقم ينقص كل ثانية حتى يصل إلى «انتهى الوقت!».
أهم سطر في المشروع هو أول سطر داخل زر «ابدأ»: if (intervalId !== null || seconds === 0) return;. هذا الشرط يمنع تشغيل مؤقت ثانٍ إذا ضغط المستخدم «ابدأ» مرتين. احذفه مؤقتاً واضغط الزر عدة مرات بسرعة، وشاهد العدّاد يجري بجنون.
ولاحظ نمط render من مشروع العدّاد: البيانات في متغير seconds، ودالة واحدة تعرضها.
جرّب بنفسك
Section titled “جرّب بنفسك”- غيّر العدّ التنازلي ليبدأ من 30 ثانية.
- اجعل الرقم يتحول إلى اللون الأحمر عندما يبقى 3 ثوانٍ أو أقل.
- أضف رسالة تظهر عند انتهاء الوقت، ثم تختفي بعد ثانيتين باستخدام
setTimeout. - تحدٍّ: حوّل العدّاد إلى ساعة إيقاف تعدّ تصاعدياً، وتعرض الوقت بالشكل
01:25.
أخطاء شائعة
Section titled “أخطاء شائعة”- كتابة الدالة بأقواس:
setTimeout(save(), 1000)تنفذsaveفوراً. الصحيحsetTimeout(save, 1000). - نسيان clearInterval: المؤقت يعمل بلا نهاية. احفظ الرقم التعريفي وأوقفه عند انتهاء الحاجة.
- توقع أن الكود ينتظر: السطر الذي يلي
setTimeoutيُنفَّذ فوراً. ما تريد تأجيله ضعه داخل الدالة المؤجلة.
اختبر نفسك
Section titled “اختبر نفسك”سؤال
كم مرة تُنفَّذ الدالة المعطاة لـ setTimeout؟
setTimeout تنفذ الدالة مرة واحدة فقط. للتكرار استخدم setInterval.
سؤال
بأي ترتيب تُطبع القيم: console.log('أ') ثم setTimeout يطبع 'ب' بمدة 0 ثم console.log('ج')؟
الكود المؤجل ينتظر حتى ينتهي الكود العادي كله، حتى لو كانت المدة صفراً.
الخلاصة
Section titled “الخلاصة”setTimeoutتنفذ دالة مرة واحدة بعد مدة بالملّي ثانية.setIntervalتكرر التنفيذ كل فترة حتى تستدعيclearInterval.- المؤقتات لا توقف البرنامج: الكود التالي يُنفَّذ فوراً، والمؤجل ينتظر دوره.
- احفظ الرقم التعريفي لتستطيع الإلغاء بـ
clearTimeoutأوclearInterval. - لا تبدأ مؤقتاً جديداً قبل التأكد من إيقاف القديم.