withTimeout وwithTimeoutOrNull
حدّد وقت التنفيذ باستخدام أغلفة المهلة وتعامل مع TimeoutCancellationException.
withTimeout وwithTimeoutOrNull درس مجاني في Kotlin Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Kotlin Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
لماذا نحتاج إلى المهلات؟
قد تظل coroutines معلقة إلى أجل غير مسمى أثناء عمليات الشبكة أو الإدخال والإخراج. تلغي withTimeout الكتلة إذا لم تكتمل خلال عدد الملليثواني المحدد.
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
withTimeout(200) {
delay(1000) // simulates slow network
println("This never prints")
}
} catch (e: TimeoutCancellationException) {
println("Timed out!")
}
}أساسيات withTimeout
تطرح withTimeout(millis) { ... } الاستثناء TimeoutCancellationException، وهو فئة فرعية من CancellationException، إذا تجاوزت الكتلة الحد الزمني.
import kotlinx.coroutines.*
suspend fun fetchData(): String {
delay(100)
return "data"
}
fun main() = runBlocking {
val result = withTimeout(500) {
fetchData()
}
println(result) // data
}withTimeoutOrNull
تعيد withTimeoutOrNull القيمة null عند انتهاء المهلة بدلًا من طرح استثناء، مما يسهّل التعامل مع المهلات كتدفق عادي.
import kotlinx.coroutines.*
fun main() = runBlocking {
val result: String? = withTimeoutOrNull(200) {
delay(1000)
"done"
}
println(result ?: "Timeout — using default")
}المهلة مع قيمة إرجاع
تعيد كلتا الدالتين قيمة التعبير الأخير في الكتلة عند النجاح.
import kotlinx.coroutines.*
fun main() = runBlocking {
val response = withTimeoutOrNull(500) {
delay(100)
mapOf("status" to 200, "body" to "OK")
}
println(response?.get("status")) // 200
}تداخل المهلات
تنتهي المهلات الداخلية أولًا. ولا تُفعَّل المهلة الخارجية إلا إذا لم تُلغِ الداخلية التنفيذ أولًا — وهذا مفيد للتمييز بين مهلات كل طلب والمهلات العامة.
import kotlinx.coroutines.*
fun main() = runBlocking {
withTimeoutOrNull(1000) { // global
withTimeoutOrNull(200) { // per-call
delay(300)
println("inner done") // won't print
} ?: println("Inner timed out")
delay(100)
println("outer still running")
}
}TimeoutCancellationException
إن TimeoutCancellationException هو CancellationException، لذلك تتعامل معه آلية coroutine على أنه إلغاء عادي ولا تمرره إلى النطاق الأب.
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try {
withTimeout(100) { delay(1000) }
} catch (e: TimeoutCancellationException) {
println("Caught in child: ${e.message}")
}
}
job.join()
println("Parent still running: ${isActive}")
}تنظيف الموارد عند انتهاء المهلة
استخدم finally داخل withTimeout لتحرير الموارد حتى عند انتهاء الوقت.
import kotlinx.coroutines.*
fun main() = runBlocking {
val result = withTimeoutOrNull(150) {
try {
println("Opening resource")
delay(300)
"result"
} finally {
println("Closing resource") // always runs
}
}
println("Result: $result")
}إعادة المحاولة مع مهلة
اجمع بين المهلة ومنطق إعادة المحاولة: نفّذ العملية مع مهلة لكل محاولة، ثم أعد المحاولة عند الحصول على نتيجة null.
import kotlinx.coroutines.*
suspend fun tryFetch(attempt: Int): String? = withTimeoutOrNull(200) {
delay(if (attempt < 3) 300L else 100L) // fails first 2 attempts
"success on attempt $attempt"
}
fun main() = runBlocking {
var result: String? = null
var attempt = 1
while (result == null) {
result = tryFetch(attempt++)
}
println(result)
}استخدام withTimeout في ViewModel
في Android ViewModels، غلّف استدعاءات المستودع باستخدام withTimeoutOrNull داخل viewModelScope.launch لعرض حالة خطأ عند بطء الاستجابات.
import kotlinx.coroutines.*
// Pseudocode pattern:
suspend fun loadUser(): String = withTimeoutOrNull(3000) {
// repo.getUser()
delay(100)
"Alice"
} ?: "Timeout — using cached data"
fun main() = runBlocking { println(loadUser()) }تنبيه بشأن الدقة
تعتمد withTimeout على موزّع coroutine. وفي الاختبارات التي تستخدم TestCoroutineScheduler، يكون الوقت افتراضيًا ويمكن تقديمه يدويًا.
import kotlinx.coroutines.*
// In unit tests with runTest:
// runTest {
// withTimeout(1000) {
// delay(999) // virtual time — completes instantly
// println("done")
// }
// }
fun main() = runBlocking {
println("Use runTest for virtual-time timeout testing")
}الاختيار بين الدالتين
استخدم withTimeout عندما تكون المهلة خطأً. واستخدم withTimeoutOrNull عندما تكون المهلة نتيجة متوقعة، مثل عدم العثور على البيانات في ذاكرة التخزين المؤقت أو التحميل المسبق الاختياري.
import kotlinx.coroutines.*
fun main() = runBlocking {
// Mandatory: throw on timeout
// withTimeout(500) { criticalOp() }
// Optional: null on timeout
val cached = withTimeoutOrNull(50) {
delay(200); "fresh"
} ?: "stale"
println(cached)
}تحقق سريع
ماذا تعيد withTimeoutOrNull عندما تتجاوز الكتلة الحد الزمني؟
مراجعة
تطرح withTimeout استثناءً عند انتهاء المهلة، بينما تعيد withTimeoutOrNull القيمة null. تلغي كلتاهما الكتلة تعاونيًا وتنفذان كتل finally. استخدم finally لتنظيف الموارد، وwithTimeoutOrNull عندما تكون المهلة نتيجة متوقعة.
الأسئلة الشائعة
هل درس «withTimeout وwithTimeoutOrNull» مجاني؟
نعم — نص درس «withTimeout وwithTimeoutOrNull» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Kotlin Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
ماذا ستتعلم في «withTimeout وwithTimeoutOrNull»؟
حدّد وقت التنفيذ باستخدام أغلفة المهلة وتعامل مع TimeoutCancellationException. تتمرن على Kotlin Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Kotlin Academy؟
لا تُشترط خبرة سابقة. Kotlin Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «withTimeout وwithTimeoutOrNull»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Kotlin Academy هذا؟
نعم. كل درس في Kotlin Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- الإلغاء التعاوني: isActive وensureActive
- withTimeout وwithTimeoutOrNull
- التنظيف باستخدام finally وNonCancellable
- انتشار الإلغاء في التسلسلات الهرمية لـ Coroutine