Under the call site's hood
In the following, we'll use the readFileSync and readFile to illustrate the underlying principles.
TypeScript call site
In Deno, we can read files like this:
import * as deno from "deno";
async function readFileTest() {
// Read file asynchronously
const data1 = await deno.readFile("test.json");
// Read file synchronously
// Note that we don't need `await` keyword.
const data2 = deno.readFile("test.json");
}The above code is very simple and straightforward, but how does Typescript read the file actually? And in the absence of libuv, how does Deno implement asynchronous calls?
In fact, the Deno APIs that need to use system calls are converted to messaging process like the following:
function readFileSync(filename: string): Uint8Array {
return res(dispatch.sendSync(...req(filename)));
}
async function readFile(filename: string): Promise<Uint8Array> {
return res(await dispatch.sendAsync(...req(filename)));
}Both the sendSync and sendAsync methods call the libdeno.send method on the underlying, and this method is a C++ binding function injected by V8. After this processing, the function call information is passed to C++.
In addition to dispatching messages, TypeScript end also needs to register a callback function to get the asynchronous result sent back from the Rust side:
libdeno.recv is also a binding function injected in V8 to register callback for receiving messages. For details on this function, please refer to the next section.
Let's take a look at how C++ consumes received messages.
C++ converter
Note: The following is pseudo libdeno.send code, just for the sake of easy understanding, the actual code is not like this.
The Send function get args and invoke the recv_cb_ . Notice that the recv_cb_ is defined in the Rust code.
The return value of the libdeno.send will be set by deno_respond:
The deno_respond is called by the recv_cb_ and will be distinguished between synchronous and asynchronous when executed. When the call is synchronous, deno_respond returns the result directly. And when the call is asynchronously, the function is triggered asynchronously and calls the callback function defined in TypeScript.
Rust executor
The journey of the function call comes to the last station. The Rust code maps the type of function call to the corresponding handler and handles synchronous and asynchronous calls based on event-loop. For details on event-loop, see the next section.
Last updated
Was this helpful?