diff --git a/src/crypto/tls/cache_test.go b/src/crypto/tls/cache_test.go
index 66854299dfa41ac4fbff3bc8187d0f4cec9d1fb3..ea6b726d5e5da2ad87fc36d67c039908e0811410 100644
--- a/src/crypto/tls/cache_test.go
+++ b/src/crypto/tls/cache_test.go
@@ -41,22 +41,12 @@ func TestCertCache(t *testing.T) {
 
 	timeoutRefCheck := func(t *testing.T, key string, count int64) {
 		t.Helper()
-
-		// Explicitly check every 1 ms up to the timeout instead of busy-looping.
-		//
-		// On single-threaded platforms like js/wasm a busy-loop might
-		// never call into the scheduler for the full timeout, meaning
-		// that if we arrive here and the cleanup hasn't already run,
-		// we'll simply loop until the timeout. Busy-loops put us at the
-		// mercy of the Go scheduler, making this test fragile on some
-		// platforms.
 		timeout := time.After(4 * time.Second)
-		check := time.After(1 * time.Millisecond)
 		for {
 			select {
 			case <-timeout:
 				t.Fatal("timed out waiting for expected ref count")
-			case <-check:
+			default:
 				e, ok := cc.Load(key)
 				if !ok && count != 0 {
 					t.Fatal("cache does not contain expected key")
@@ -68,6 +58,15 @@ func TestCertCache(t *testing.T) {
 					return
 				}
 			}
+			// Explicitly yield to the scheduler.
+			//
+			// On single-threaded platforms like js/wasm a busy-loop might
+			// never call into the scheduler for the full timeout, meaning
+			// that if we arrive here and the cleanup hasn't already run,
+			// we'll simply loop until the timeout. Busy-loops put us at the
+			// mercy of the Go scheduler, making this test fragile on some
+			// platforms.
+			runtime.Gosched()
 		}
 	}