Menu
flag Ar iconالعربيةdown icon

Sleep في TypeScript: كيف تنتظر أو تؤخر التنفيذ

لا يوجد في TypeScript دالة sleep مدمجة، لكن سطرًا واحدًا يعطيك واحدة: دالة تعيد Promise<void> يحلّها setTimeout. تعرّف على طريقة انتظارها بـ await، والتوقف داخل الحلقات، وإعادة المحاولة مع تأخير، وإلغاء الانتظار، ولماذا لا يوجد sleep حاجب في JavaScript.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

لا يوجد في TypeScript دالة sleep مدمجة. اكتب دالة تعيد Promise<void> يحلّها setTimeout بعد مدة التأخير، ثم انتظرها بـ await داخل دالة async:

توقف await sleep(300) الدالة main وحدها. البرنامج لا يتجمد: المؤقتات والدوال غير المتزامنة الأخرى وعمليات الإدخال والإخراج تستمر في العمل أثناء الانتظار.

كيف تعمل دالة sleep

يجدول setTimeout(resolve, ms) استدعاء resolve بعد ms ملّي ثانية، واستدعاء resolve يُنهي الـ promise. وawait على ذلك الـ promise تعلّق الدالة غير المتزامنة حتى تلك اللحظة.

وسيط النوع <void> مهم. التعبير new Promise(...) المستقل لا يستنتج نوعه من استدعاءات resolve، لذلك دونه تعيد sleep النوع Promise<unknown>. وvoid هو ما يسمح باستدعاء resolve دون قيمة: في Promise<number> يكون resolve() دون وسيط خطأ ترجمة. وعندما يكون للدالة نوع إعادة مصرّح به، يمكن وضع وسيط النوع هناك بدلًا من ذلك:

يضمن setTimeout حدًا أدنى لا وقتًا دقيقًا: تعمل الدالة عندما تنقضي المدة وتكون حلقة الأحداث متفرغة. توقّع فارقًا ببضع ملّي ثوان.

الانتظار داخل حلقة

await sleep() داخل حلقة for أو for...of توقف التنفيذ بين التكرارات، وهكذا تضبط وتيرة العمل (حدود المعدل، والاستطلاع الدوري، والحركات في الطرفية):

هذا لا يعمل داخل forEach: فهي تتجاهل الـ promise الذي تعيده كل دالة async، فتبدأ كل التكرارات معًا ولا شيء ينتظر. استخدم حلقة for أو for...of، كما هو مشروح في صفحة async/await.

إعادة المحاولة مع تأخير

استخدام حقيقي شائع: جرّب عملية، وإذا فشلت انتظر وحاول مجددًا، مع مضاعفة مدة الانتظار في كل مرة (التراجع الأسي، exponential backoff).

وجود return await fn() داخل try مهم: دون await سيُعاد الـ promise المرفوض قبل أن تتمكن catch من رؤيته.

sleep قابلة للإلغاء

لا يمكن مقاطعة sleep العادية. لإيقاف الانتظار مبكرًا (ضغط المستخدم على إلغاء، أو بدأ إيقاف التشغيل)، مرّر AbortSignal وامسح المؤقت عندما تُطلق الإشارة:

ينتهي البرنامج فور الإلغاء لأن المؤقت الطويل مُسح. دون clearTimeout كانت Node ستستمر في العمل حتى تنقضي الثواني الخمس.

مؤقتات Promise المدمجة في Node

توفر Node نسخة من setTimeout تعمل بالـ promises في الوحدة node:timers/promises، لذلك يمكنك في كود Node استيرادها بدلًا من كتابة الدالة المساعدة. وهي تقبل أيضًا قيمة يُحل بها الـ promise وAbortSignal:

import { setTimeout as sleep } from "node:timers/promises";

async function main() {
    await sleep(1000);                              // wait one second
    const result = await sleep(500, "done");        // resolves with "done"
    const ac = new AbortController();
    await sleep(10_000, undefined, { signal: ac.signal }); // cancellable
}

تأتي الأنواع من @types/node (npm i -D @types/node). هذه الوحدة غير موجودة في المتصفحات، حيث تكون الدالة المساعدة ذات السطر الواحد هي الخيار الذي يعمل في كل مكان.

لا يوجد sleep حاجب

اللغات التي فيها خيوط لها دالة sleep تحجب الخيط الحالي. أما JavaScript فتشغّل كودك على خيط واحد مع حلقة أحداث، لذلك سيجمّد sleep الحاجب كل شيء آخر: لا تنطلق أي مؤقتات، ولا تُعالج أي استجابات شبكة، وتتوقف الصفحة في المتصفح عن الاستجابة. الحلقة المشغولة التي تدور حتى تتجاوز الساعة وقتًا معينًا تفعل ذلك بالضبط، وليست أبدًا الأداة الصحيحة.

الـ sleep غير المتزامنة هي طريقة الانتظار في JavaScript وTypeScript: تُعلّق الدالة، ويبقى الخيط متفرغًا، وتستأنف الدالة عندما يُطلق المؤقت. يستطيع Atomics.wait الحجب فعلًا، لكن على SharedArrayBuffer فقط، وتمنعه المتصفحات على الخيط الرئيسي؛ فهو موجود لتنسيق خيوط الـ workers، لا للتأخير.

الأسئلة الشائعة

كيف أستخدم sleep في TypeScript؟

عرّف const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)); واستدعِ await sleep(1000) داخل دالة async. توقف هذه الدالة لمدة ثانية تقريبًا دون أن تحجب بقية البرنامج.

هل توجد دالة sleep مدمجة في TypeScript؟

لا. يضيف TypeScript الأنواع إلى JavaScript وليس له مكتبة وقت تشغيل خاصة به، وليس في JavaScript دالة sleep. في Node يمكنك استيراد واحدة: import { setTimeout as sleep } from "node:timers/promises". وفي المتصفح اكتب الدالة المساعدة ذات السطر الواحد.

لماذا تحتاج sleep إلى await؟

يعيد sleep(1000) promise فورًا؛ وawait وحدها توقف الدالة غير المتزامنة المحيطة إلى أن يُحل. دون await يعمل السطر التالي في الحال. ولا تعمل await إلا داخل دالة async (أو على المستوى الأعلى في وحدة ES).

هل يمكن حجب الخيط بـ sleep متزامن في TypeScript؟

ليس في الكود العادي. تعمل JavaScript على خيط واحد مع حلقة أحداث، وحلقة الانتظار المشغول تجمّد كل شيء: المؤقتات، ودوال الاستجابة للشبكة، والصفحة كلها. استخدم sleep غير المتزامنة بدلًا من ذلك. يستطيع Atomics.wait حجب خيط في Node أو في worker، لكنه مخصص للتنسيق منخفض المستوى بين الـ workers، لا للتأخير.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن