Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deno top level await

Was reading the homepage of deno the new JS runtime

I saw the following code:

import { serve } from "https://deno.land/[email protected]/http/server.ts";
const s = serve({ port: 8000 });
console.log("http://localhost:8000/");
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?

like image 773
Willem van der Veen Avatar asked May 20 '20 15:05

Willem van der Veen


People also ask

How do you await top level?

Top level await You can use the await keyword on its own (outside of an async function) at the top level of a module. This means that modules with child modules that use await will wait for the child modules to execute before they themselves run, all while not blocking other child modules from loading.

Does Nodejs have top level await?

Top-level await enables developers to use the await keyword outside of async functions. Starting from Node. js v14 top-level await is available and it is only available in ES modules. This means you can not use it with common js modules.

How do you use await in top level TypeScript?

To use top-level await in TypeScript, you have to set “target” to es2017 or higher. The “module” option in “tsconfig. json” has to be set to esnext or system . Your code also has to run on Node.

Does JavaScript wait for await?

The keyword Await makes JavaScript wait until the promise returns a result. It has to be noted that it only makes the async function block wait and not the whole program execution.


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

like image 121
Marcos Casagrande Avatar answered Oct 18 '22 21:10

Marcos Casagrande


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 "https://deno.land/[email protected]/http/server.ts";
const s = serve({ port: 8000 });
console.log("http://127.0.0.1:8000/");

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 "https://deno.land/[email protected]/http/server.ts";
const s = serve({ port: 8000 });
console.log("http://127.0.0.1:8000/");

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
like image 38
Redu Avatar answered Oct 18 '22 21:10

Redu