Documentação
Modo de compatibilidade
Conceitos
Env

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 mesmo napi_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 o napi_env para fins de reutilização geral e passar o napi_env entre instâncias do mesmo addon em diferentes threads Worker não é permitido. O napi_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 para napi_add_env_cleanup_hook e napi_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
})