Library
await — waiting for a promise
await unwraps a promise to its value, suspending only the current task while other work keeps running.
since 0.1.0-alpha.1linuxwindowswasm
Description
await expr waits for expr and evaluates to its value. When expr is a Promise<T>, the
result has type T. There is no async keyword and no function coloring: any function may
await, and a function that returns a Promise<T> is simply the asynchronous form of a function
that returns T.
What happens at an await depends on the state of the promise.
- If
expris not a promise,awaityields it unchanged. - If the promise is already ready,
awaitcarries on immediately. It does not give any other work a chance to run; it is as cheap as reading the value. - Otherwise the current task is suspended. Everything else keeps running while it waits:
timers fire, sockets deliver data, and other tasks resume. When the promise is settled, the task
continues after the
awaitwith the value. Seelang.tasksfor what a task is.
Timers resolve promises; await parks until each one is ready
Promise<int> after(int ms, int value) {
Promise<int> p = Promise();
std::sysTimerStart(ms, 0, (n) => {
console.writeln("timer " + ms.toString() + "ms fired");
p.resolve(value);
});
return p;
}
void run() {
// created together, due at 30, 20 and 10 ms
Promise<int> a = after(30, 1);
Promise<int> b = after(20, 2);
Promise<int> c = after(10, 3);
// awaited in creation order; the timers still fire in due-time order
int x = await a;
console.writeln("got a = " + x.toString());
int y = await b;
int z = await c;
console.writeln("got b = " + y.toString() + ", c = " + z.toString());
console.writeln("total " + (x + y + z).toString());
}
run();
timer 10ms fired
timer 20ms fired
timer 30ms fired
got a = 1
got b = 2, c = 3
total 6
Rules
await exprhas the value of the promise's content, orexpritself whenexpris not a promise. APromise<void>yields no usable value.- An
awaiton a ready promise does not suspend. It never lets another task run. A loop of awaits on ready promises is plain computation, not cooperation: other work only gets a turn at the first await that really has to wait. - A suspended task resumes in completion order. Among the tasks of one thread that are ready to continue, they resume first-come first-served. Do not rely on any other order.
- Anything can happen at an
await. While a task is suspended, other tasks on the same thread run and may read or change shared state.awaitmarks the places where that can happen. - Failure at an await. An
awaiton aWorkerwhose body threw rethrows the failure there, wheretry/catchcan handle it. If the event loop has no work left that could ever settle the promise, theawaitthrows aRuntimeExceptionwith the messageawait: event loop drained with promise unresolved; it can be caught. - An exception thrown in a callback is never delivered to an unrelated
await. A timer or socket callback runs as its own task, so an uncaught throw there ends the program through the usual uncaught-exception path (exit status1). awaitcannot be used insidecomptimecode. It is a compile error there.then(callback)does not suspend anything; it runs the callback synchronously, at the point where the promise is resolved.
Examples
A ready promise does not suspend, so the pending timer callback cannot run until a real wait begins:
Ready awaits do not suspend
Promise<int> after(int ms, int value) {
Promise<int> p = Promise();
std::sysTimerStart(ms, 0, (n) => p.resolve(value));
return p;
}
std::sysTimerStart(0, 0, (n) => console.writeln("timer callback ran"));
int a = await Promise(5);
console.writeln("ready await did not suspend: ${a}");
int b = await after(10, 6);
console.writeln("suspended await resumed: ${b}");
ready await did not suspend: 5
timer callback ran
suspended await resumed: 6
A promise that nothing can ever resolve is detected, not waited on forever:
Awaiting a promise nobody can resolve
Promise<int> p = Promise();
try {
int x = await p;
console.writeln("got ${x}");
} catch (IException e) {
console.writeln("caught: ${e.message}");
}
caught: await: event loop drained with promise unresolved
A throw inside a timer callback is not delivered to the await that happens to be waiting. The
program ends with Uncaught RuntimeException: boom and the await reports its own failure:
Promise<int> p = Promise();
std::sysTimerStart(5, 0, (n) => { throw RuntimeException("boom"); });
try { int x = await p; } catch (IException e) {
console.writeln("caught: " + e.message); // the drained-loop message, never "boom"
}