Async & Error Handling
Tova provides utility functions for working with asynchronous code and wrapping fallible operations into Result types.
Error Handling
try_fn
tryFn(fn) -> ResultWraps a synchronous function call in a try/catch and returns Ok(value) on success or Err(message) on failure.
tryFn(fn() toInt("42"))
// Ok(42)
tryFn(fn() {
data = jsonParse("bad json").unwrap()
data.name
})
// Err("Called unwrap on Err: ...")// Safe division
fn safe_divide(a, b) {
tryFn(fn() {
assert(b != 0, "division by zero")
a / b
})
}
safe_divide(10, 2) // Ok(5)
safe_divide(10, 0) // Err("division by zero")try_async
tryAsync(fn) -> Promise[Result]Wraps an async function call in a try/catch and returns a Promise of Ok(value) or Err(message).
async fn main() {
result = await tryAsync(fn() fetch("/api/data"))
match result {
Ok(response) => process(response)
Err(msg) => print("Request failed: {msg}")
}
}
main()Concurrency
parallel
parallel(list) -> Promise[List]Runs multiple promises concurrently and waits for all to complete. A wrapper around Promise.all.
async fn main() {
results = await parallel([
fetch("/api/users"),
fetch("/api/posts"),
fetch("/api/comments")
])
// [users_response, posts_response, comments_response]
}
main()race
race(promises) -> PromiseReturns a promise that resolves or rejects as soon as the first promise in the list settles. The result is the value (or error) from the first promise to complete.
async fn main() {
// Use the fastest API response
result = await race([
fetch("https://api1.example.com/data"),
fetch("https://api2.example.com/data")
])
}
main()async fn main() {
// Implement a timeout using the timeout() function
result = await tryAsync(fn() {
timeout(fetch("/api/slow"), 5000)
})
}
main()timeout
timeout(promise, ms) -> PromiseAdds a timeout to a promise. If the promise does not resolve within ms milliseconds, it rejects with a timeout error.
async fn main() {
// Fail if API takes longer than 5 seconds
result = await tryAsync(fn() {
timeout(fetch("/api/slow-endpoint"), 5000)
})
match result {
Ok(data) => process(data)
Err(msg) => print("Timed out or failed: {msg}")
}
}
main()retry
retry(fn, opts?) -> PromiseRetries an async function up to times attempts with configurable delay and exponential backoff.
Options:
times-- number of attempts (default: 3)delay-- base delay in ms between retries (default: 100)backoff-- multiplier for exponential backoff (default: 1)
async fn main() {
// Retry up to 3 times with default settings
var data = await retry(fn() fetch("/api/unreliable"))
// Retry 5 times with exponential backoff
data = await retry(
fn() fetch("/api/flaky"),
{ times: 5, delay: 200, backoff: 2 }
)
// Delays: 200ms, 400ms, 800ms, 1600ms between retries
}
main()sleep
sleep(ms) -> PromiseReturns a promise that resolves after ms milliseconds. Useful for delays, polling intervals, and timeouts.
async fn main() {
// Wait 1 second
await sleep(1000)
// Polling with delay
loop {
status = await check_status()
if status == "ready" { break }
await sleep(500)
}
}
main()parallel_map
parallelMap(arr, fn, numWorkers?) -> Promise[List]Distributes an array across worker threads and applies fn to each element in parallel. Returns a promise resolving to the mapped results.
arr: The input array to processfn: A mapping function applied to each element. Must be serializable (no closures over external state)numWorkers(optional): Number of worker threads. Defaults tonavigator.hardwareConcurrency(browser) or 4 (server)
The worker pool is persistent — workers are created once and reused across calls, avoiding thread creation overhead.
async fn main() {
// Map in parallel across all CPU cores
var results = await parallelMap(items, fn(item) {
expensive_transform(item)
})
// Limit to 2 workers
results = await parallelMap(items, fn(x) x * 2, 2)
}
main()For small arrays (< 4 elements) or a single worker, parallel_map falls back to synchronous map to avoid overhead.
Date & Time
For date/time functions (now, now_iso, date_parse, date_format, date_add, date_diff, date_from, date_part, time_ago), see the Date & Time page.
Pipeline Examples
async fn main() {
// Fetch with retry and timeout, returning Result
await tryAsync(fn() {
retry(fn() timeout(fetch("/api/data"), 3000), { times: 3 })
})
// Parallel fetch with error handling
urls = ["/api/a", "/api/b", "/api/c"]
results = await parallel(
map(urls, fn(url) tryAsync(fn() fetch(url)))
)
// List of Ok/Err results
}
main()