Kotlin Academy · บทเรียน

withTimeout และ withTimeoutOrNull

จำกัดเวลาการทำงานด้วยตัวห่อ timeout และจัดการ TimeoutCancellationException

บทเรียน 2 จาก 413 ขั้นตอน

withTimeout และ withTimeoutOrNull เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดจึงต้องกำหนดเวลาสิ้นสุด

โคโรทีนอาจค้างอยู่ไม่สิ้นสุดระหว่างทำงานกับเครือข่ายหรือการรับส่งข้อมูลเข้าออก 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 ดังนั้นกลไกของโคโรทีนจึงถือว่าเป็นการยกเลิกตามปกติ และจะไม่ส่งต่อไปยังขอบเขตแม่

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

ใน ViewModel ของแอนดรอยด์ ให้ครอบการเรียกคลังข้อมูลด้วย 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 อาศัยตัวจัดส่งโคโรทีน ในการทดสอบที่ใช้ 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 เมื่อการหมดเวลาเป็นผลลัพธ์ที่คาดหมายได้

เริ่มต้นได้ฟรี

เรียนรู้ Kotlin ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
51
บทเรียน
203

คำถามที่พบบ่อย

บทเรียน “withTimeout และ withTimeoutOrNull” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “withTimeout และ withTimeoutOrNull” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “withTimeout และ withTimeoutOrNull”

จำกัดเวลาการทำงานด้วยตัวห่อ timeout และจัดการ TimeoutCancellationException คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “withTimeout และ withTimeoutOrNull” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม

ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การยกเลิกร่วมมือกัน: isActive และ ensureActive
  2. withTimeout และ withTimeoutOrNull
  3. การเก็บกวาดด้วย finally และ NonCancellable
  4. การส่งต่อการยกเลิกในลำดับชั้น Coroutine
← กลับไปที่ Kotlin Academy