async fn
You must enable the async or tokio_rt feature in napi to use async fn:
[dependencies]
napi = { version = "3", features = ["async"] }Tokio integration
You can do a lot of async/multi-threaded work with AsyncTask and ThreadsafeFunction, but sometimes you may want to use the crates from the Rust async ecosystem directly.
NAPI-RS supports the tokio runtime by default. If you await a tokio future in async fn, NAPI-RS will execute it in the tokio runtime and convert it into a JavaScript Promise.
use napi::bindgen_prelude::*;
use napi_derive::napi;
use tokio::fs;
#[napi]
pub async fn read_file_async(path: String) -> Result<Buffer> {
let content = fs::read(path).await?;
Ok(content.into())
}⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️
export function readFileAsync(path: string): Promise<Buffer>Unsafe &mut self
In some cases, you may need to use &mut self in an async fn. However, this is unsafe in NAPI-RS, because the self is also owned by the Node.js runtime. You cannot ensure that the self is only owned by Rust.
use napi_derive::napi;
#[napi]
pub struct Engine {}
#[napi]
impl Engine {
#[napi]
pub async fn run(&mut self) {}
}error: &mut self in async napi methods should be marked as unsafe
--> src/lib.rs:9:18
|
9 | pub async fn run(&mut self) {}
| ^^^You need to mark the fn as unsafe to use &mut self in an async fn.
use napi_derive::napi;
#[napi]
pub struct Engine {}
#[napi]
impl Engine {
#[napi]
pub async unsafe fn run(&mut self) {}
}Auto reference
Usually, JavaScript values are only valid within a function call. async fn is not the case, the JavaScript values may be garbage collected in any await point.
See Understanding Lifetime for more details.
There are 3 kinds of parameters are automatically turned into Reference types:
&self&mut selfThis<T>
Considering the following example:
use napi::bindgen_prelude::*;
use napi_derive::napi;
#[napi]
pub struct NativeClass {
name: String,
}
#[napi]
impl NativeClass {
#[napi(constructor)]
pub fn new(name: String) -> Self {
Self { name }
}
#[napi]
pub async fn sleep(&self, delay: u32) -> Result<&str> {
tokio::time::sleep(std::time::Duration::new(delay as u64, 0)).await;
Ok(&self.name)
}
}const nativeClass = new NativeClass('Brooklyn')
const name = await nativeClass.sleep(1)
console.log(name) // BrooklynThere is a implicit napi_create_reference call for the JavaScript Object value which holds the NativeClass before the async fn call; and a implicit napi_delete_reference call after the async fn call.
This strategy makes sure the NativeClass is alive during the async fn call.