Deno top level await

Was reading the homepage of deno the new JS runtime

I saw the following code:

import { serve } from ""; const s = serve({ port: 8000 }); console.log(""); for await (const req of s) { req.respond({ body: "Hello World\n" }); } 

I never have seen the following syntax (for await):

for await (const req of s) { req.respond({ body: "Hello World\n" }); } 

What is this kind of syntax?

Is it specific to deno or is it a top-level-await found in this tc39 proposal?

Edit: Why can it be used outside of an async function?

1

2 Answers

for await...of statement is used to iterate through async iterators, and serve returns an async iterator, where each iteration will be a new incoming request.

Is it specific to deno or is it a top-level-await found in this tc39 proposal?

No, it's not specific to Deno and it's a different proposal than top-level await.


Here's a simple example of an asyncIterator that works in browsers too (non-deno exclusive)

const obj = { async *[Symbol.asyncIterator]() { for(let i = 0; i < 10; i++) yield new Promise(resolve => setTimeout(() => resolve(i), 100)); } }; (async() => { // You don't need the wrapper if the environment // supports top-level await, e.g: Deno for await(const i of obj) console.log(`${i}`, new Date()) })();

Edit: Why can it be used outside of an async function?

Because Deno supports top-level await

4

This also drew my attention when i decided to use Deno. I like Deno as it is native on ES6 like Promises, Import - Export and also you don't even need npm like in Node, just import the package from an url.

Now this async and await abstractions are ok for the sake of simplification of the code but it also hides many things, that some people basically have difficult time in understanding what exactly is going on.

I would first advise you to spare some time and read this beautiful article on asychronous iteration.

The thing is, in the very basic code to start a server that's given like

import { serve } from ""; const s = serve({ port: 8000 }); console.log(""); for await (const req of s) { req.respond({ body: "Hello World\n" }); } 

you have to accept that for some reason the for await loop is turning once, when a request is received. Actually that's exactly what it does. The machine which drives the asychronous iteration and promises are hidden.

Now we should know that the s in;

const s = serve({ port: 8000 }); 

is in fact an asynchronous iterable object. So it has a method called [Symbol.asyncIterator]. When you invoke it like s[Symbol.asyncIterator]() you get an asynchronous iterator object with a next method. Normally with synch iterators when the next() is called you receive an object like {value: "stg", done: false} but in async iterators a Promise is received. This promise, once resolves when a request is received (or rejects if an error happens) gives us an object like

{ value: ServerRequest Object , done : false } 

So the above code can also be written like;

import { serve } from ""; const s = serve({ port: 8000 }); console.log(""); var rqs = s[Symbol.asyncIterator](), srv = (app,rqs) => rqs.next().then(rq => (app(rq.value), srv(app,rqs))), app = req => req.respond({body: "Hello World\n"}); srv(app,rqs); // receive requests and handle them with your app 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like