jsrosetta

Async

Timers: setTimeout and setInterval

How Node.js's setTimeout and setInterval compare to time.AfterFunc/Ticker (Go), std::thread (Rust), Task.sleep (Swift), and ScheduledExecutorService (Java).

Minimum versions
Node.js ≥ 12.20Go ≥ 1.0Rust ≥ 1.58Swift ≥ 5.7Java ≥ 25
Verified on
Node.js 24.12.0Go 1.27.1Rust 1.98.1Swift 6.2.4Java 25.0.4.1

Node.js code is an ES module: save it as .mjs or set "type": "module" in package.json.

Node.js runs setTimeout/setInterval callbacks on the event loop, so the program stays alive until the callback queue is empty. For the one-shot version, Go, Rust, and Java all run the callback on a separate thread/goroutine — without something to keep the main thread around (sync.WaitGroup, JoinHandle::join, CountDownLatch), the program can exit before the callback runs — while Swift is the exception: Task.sleep runs directly inside the current task, so no separate waiting mechanism is needed. The repeating version is different: Go's time.Ticker and Rust's channel don't "run a callback" at all — they send a tick on a channel/queue that the caller has to read itself, and Swift's AsyncStream works the same way (it yields ticks for a for await loop to read); Java, though, still runs a real callback via scheduleAtFixedRate, just like setInterval.

Running something once after a delay (setTimeout / time.AfterFunc)

setTimeout(callback, 1000);
 
function callback() {
  console.log("called"); // → called (after ~1s)
}

Running on a repeating schedule (setInterval / time.Ticker)

let i = 0;
 
const id = setInterval(callback, 1000);
 
function callback() {
  console.log("called", i);
 
  if (i === 3) {
    clearInterval(id);
  }
 
  i++;
}
// → called 0
// → called 1
// → called 2
// → called 3

Reference: github.com/miguelmota/golang-for-nodejs-developers#timeout