Env
Nas documentações do Node.js
napi_env
é usado para representar um contexto que a implementação subjacente do N-API pode usar para persistir o estado específico da VM. Esta estrutura é passada para funções nativas quando são invocadas, e deve ser passada de volta ao fazer chamadas N-API. Especificamente, o mesmonapi_env
que foi passado quando a função nativa inicial foi chamada deve ser passado para quaisquer chamadas N-API aninhadas subsequentes. Armazenar em cache onapi_env
para fins de reutilização geral e passar onapi_env
entre instâncias do mesmo addon em diferentes threads Worker não é permitido. Onapi_env
se torna inválido quando uma instância de um addon nativo é descarregada. A notificação deste evento é entregue por meio dos callbacks fornecidos paranapi_add_env_cleanup_hook
enapi_set_instance_data
.
Env
é uma abstração em camada de Rust
sobre napi_env
. Ao escrever Add-ons do Node.js em C/C++
, qualquer chamada N-API passa por napi_env
, e da mesma forma em Rust
, qualquer chamada de API passa pela estrutura de dados Env
. No napi-rs
, existem quatro maneiras de interagir com Env
.
1. CallContext em js_function
js_function
é uma forma de definir uma JavaScript function
em Rust
:
#[js_function(1)]
fn hello(ctx: CallContext) -> Result<JsString> {
let argument_one = ctx.get::<JsString>(0)?.into_utf8()?;
ctx.env.create_string_from_std(format!("{} world!", argument_one.as_str()?))
}
Há um campo env
na estrutura CallContext
.
A funcionalidade do Env
pode ser encontrada na documentação do Env (opens in a new tab).
2. contextless_function
contextless_function
é muito semelhante a js_function
, exceto que contextless_function
não terá o Contexto desta JavaScript function
.
O que significa que em contextless_function
você não pode obter os arguments, this ou qualquer outro dado relacional de contexto da função. Mas isso será mais eficiente em termos de desempenho, então pode ser usado em cenários sensíveis ao desempenho.
#[contextless_function]
fn just_return_hello(env: Env) -> ContextlessResult<JsString> {
env.create_string("hello").map(Some)
}
3. Método resolve/reject
no Task trait
O Task trait é um pouco complicado, veja sua documentação para uma entendimento melhor.
Env
será passado para seus métodos resolve
e reject
. Os dois métodos serão chamados na thread principal quando a tarefa assíncrona no pool de threads for concluída.
struct PlusOneAsync(u32);
impl Task for PlusOneAsync {
type Output = u32;
type JsValue = JsNumber;
fn compute(&mut self) -> Result<Self::Output> {
Ok(self.0 + 1)
}
fn resolve(self, env: Env, output: Self::Output) -> Result<Self::JsValue> {
env.create_uint32(output)
}
}
#[js_function(1)]
fn async_plus_one(ctx: CallContext) -> Result<JsNumber> {
let input_number: u32 = ctx.get::<JsNumber>(0)?.try_into()?;
let task = PlusOneAsync(input_number);
ctx.env.spawn(task).map(|t| t.promise_object())
}
asyncPlusOne(1).then((result) => {
console.log(result) // 2
})
4. ThreadSafeCallContext
em Thread safe function
#[js_function(1)]
fn thread_safe_function(ctx: CallContext) -> Result<JsUndefined> {
let callback: JsFunction = ctx.get(0)?;
let tsfn = ctx.create_threadsafe_function(&callback, 0, |ctx: ThreadSafeCallContext<u32>| {
ctx.env.create_uint32(ctx.value).map(|js_value| vec![js_value])
})?;
std::thread::spawn(move || {
tsfn.call(Ok(1), ThreadsafeFunctionCallMode::NonBlocking);
});
ctx.env.get_undefined()
}
threadSafeFunction((err, value) => {
if (err) {
console.error(err)
process.exit(1)
}
console.log(value) // 1
})