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