feat(napi): provide reject method in Task trait

Do some cleanup logic if needed
This commit is contained in:
LongYinan 2020-12-18 11:32:07 +08:00
parent 08e5804c3b
commit 9d38689426
No known key found for this signature in database
GPG key ID: A3FFE134A3E20881
4 changed files with 38 additions and 8 deletions

View file

@ -93,10 +93,13 @@ unsafe extern "C" fn complete<T: Task>(
let value_ptr = mem::replace(&mut work.value, Ok(mem::MaybeUninit::zeroed())); let value_ptr = mem::replace(&mut work.value, Ok(mem::MaybeUninit::zeroed()));
let deferred = mem::replace(&mut work.deferred, ptr::null_mut()); let deferred = mem::replace(&mut work.deferred, ptr::null_mut());
let napi_async_work = mem::replace(&mut work.napi_async_work, ptr::null_mut()); let napi_async_work = mem::replace(&mut work.napi_async_work, ptr::null_mut());
let value = value_ptr.and_then(move |v| { let value = match value_ptr {
Ok(v) => {
let output = v.assume_init(); let output = v.assume_init();
work.inner_task.resolve(Env::from_raw(env), output) work.inner_task.resolve(Env::from_raw(env), output)
}); }
Err(e) => work.inner_task.reject(Env::from_raw(env), e),
};
match check_status!(status).and_then(move |_| value) { match check_status!(status).and_then(move |_| value) {
Ok(v) => { Ok(v) => {
let status = sys::napi_resolve_deferred(env, deferred, v.raw()); let status = sys::napi_resolve_deferred(env, deferred, v.raw());

View file

@ -1,11 +1,17 @@
use crate::js_values::NapiValue; use crate::{js_values::NapiValue, Env, Error, Result};
use crate::{Env, Result};
pub trait Task: Send { pub trait Task: Send + Sized {
type Output: Send + Sized + 'static; type Output: Send + Sized + 'static;
type JsValue: NapiValue; type JsValue: NapiValue;
/// Compute logic in libuv thread
fn compute(&mut self) -> Result<Self::Output>; fn compute(&mut self) -> Result<Self::Output>;
/// Into this method if `compute` return `Ok`
fn resolve(self, env: Env, output: Self::Output) -> Result<Self::JsValue>; fn resolve(self, env: Env, output: Self::Output) -> Result<Self::JsValue>;
/// Into this method if `compute` return `Err`
fn reject(self, _env: Env, err: Error) -> Result<Self::JsValue> {
Err(err)
}
} }

View file

@ -12,3 +12,14 @@ test('should be able to spawn thread with ref value', async (t) => {
const result = await bindings.testSpawnThreadWithRef(Buffer.from(fixture)) const result = await bindings.testSpawnThreadWithRef(Buffer.from(fixture))
t.is(result, fixture.length) t.is(result, fixture.length)
}) })
test('should be able to spawn with error', async (t) => {
const fixture = Array.from({ length: 10 }).fill('0').join('')
const err = new Error('Unreachable')
try {
await bindings.testSpawnThreadWithRef(Buffer.from(fixture))
throw err
} catch (e) {
t.not(e, err)
}
})

View file

@ -1,6 +1,8 @@
use std::convert::TryInto; use std::convert::TryInto;
use napi::{CallContext, Env, JsBuffer, JsBufferValue, JsNumber, JsObject, Ref, Result, Task}; use napi::{
CallContext, Env, Error, JsBuffer, JsBufferValue, JsNumber, JsObject, Ref, Result, Task,
};
struct ComputeFib { struct ComputeFib {
n: u32, n: u32,
@ -56,6 +58,9 @@ impl Task for CountBufferLength {
type JsValue = JsNumber; type JsValue = JsNumber;
fn compute(&mut self) -> Result<Self::Output> { fn compute(&mut self) -> Result<Self::Output> {
if self.data.len() == 10 {
return Err(Error::from_reason("len can't be 5".to_string()));
}
Ok((&self.data).len()) Ok((&self.data).len())
} }
@ -63,6 +68,11 @@ impl Task for CountBufferLength {
self.data.unref(env)?; self.data.unref(env)?;
env.create_uint32(output as _) env.create_uint32(output as _)
} }
fn reject(self, env: Env, err: Error) -> Result<Self::JsValue> {
self.data.unref(env)?;
Err(err)
}
} }
#[js_function(1)] #[js_function(1)]