feat(napi): implement AsyncTask with AbortSignal support

This commit is contained in:
LongYinan 2021-11-04 18:44:06 +08:00
parent d36c303dec
commit e74fe2fb94
No known key found for this signature in database
GPG key ID: C3666B7FC82ADAD7
17 changed files with 114 additions and 98 deletions

View file

@ -154,15 +154,16 @@ pub fn test_tsfn_with_ref(ctx: CallContext) -> Result<JsUndefined> {
let callback = ctx.get::<JsFunction>(0)?;
let options = ctx.get::<JsObject>(1)?;
let options_ref = ctx.env.create_reference(options)?;
let tsfn =
ctx
.env
.create_threadsafe_function(&callback, 0, |ctx: ThreadSafeCallContext<Ref<()>>| {
ctx
.env
.get_reference_value_unchecked::<JsObject>(&ctx.value)
.and_then(|obj| ctx.value.unref(ctx.env).map(|_| vec![obj]))
})?;
let tsfn = ctx.env.create_threadsafe_function(
&callback,
0,
|mut ctx: ThreadSafeCallContext<Ref<()>>| {
ctx
.env
.get_reference_value_unchecked::<JsObject>(&ctx.value)
.and_then(|obj| ctx.value.unref(ctx.env).map(|_| vec![obj]))
},
)?;
thread::spawn(move || {
tsfn.call(Ok(options_ref), ThreadsafeFunctionCallMode::Blocking);

View file

@ -22,7 +22,7 @@ impl Task for ComputeFib {
Ok(fibonacci_native(self.n))
}
fn resolve(self, env: Env, output: Self::Output) -> Result<Self::JsValue> {
fn resolve(&mut self, env: Env, output: Self::Output) -> Result<Self::JsValue> {
env.create_uint32(output)
}
}
@ -63,15 +63,18 @@ impl Task for CountBufferLength {
Ok((&self.data).len())
}
fn resolve(self, env: Env, output: Self::Output) -> Result<Self::JsValue> {
self.data.unref(env)?;
fn resolve(&mut self, env: Env, output: Self::Output) -> Result<Self::JsValue> {
env.create_uint32(output as _)
}
fn reject(self, env: Env, err: Error) -> Result<Self::JsValue> {
self.data.unref(env)?;
fn reject(&mut self, env: Env, err: Error) -> Result<Self::JsValue> {
Err(err)
}
fn finally(&mut self, env: Env) -> Result<()> {
self.data.unref(env)?;
Ok(())
}
}
#[js_function(1)]

View file

@ -43,7 +43,7 @@ Generated by [AVA](https://avajs.dev).
export function concatUtf16(s: string): string␊
export function concatLatin1(s: string): string␊
export function withoutAbortController(a: number, b: number): Promise<number>
export function withAbortController(a: number, b: number, ctrl: AbortController): Promise<number>
export function withAbortController(a: number, b: number, signal: AbortSignal): Promise<number>
export function getBuffer(): Buffer␊
export class Animal {␊
readonly kind: Kind␊

View file

@ -167,9 +167,11 @@ test('async task without abort controller', async (t) => {
t.is(await withoutAbortController(1, 2), 3)
})
test('async task with abort controller', async (t) => {
const MaybeTest = typeof AbortController !== 'undefined' ? test : test.skip
MaybeTest('async task with abort controller', async (t) => {
const ctrl = new AbortController()
const promise = withAbortController(1, 2, ctrl)
const promise = withAbortController(1, 2, ctrl.signal)
try {
ctrl.abort()
await promise
@ -178,3 +180,9 @@ test('async task with abort controller', async (t) => {
t.is((err as Error).message, 'AbortError')
}
})
MaybeTest('abort resolved task', async (t) => {
const ctrl = new AbortController()
await withAbortController(1, 2, ctrl.signal).then(() => ctrl.abort())
t.pass('should not throw')
})

View file

@ -33,7 +33,7 @@ export function concatStr(mutS: string): string
export function concatUtf16(s: string): string
export function concatLatin1(s: string): string
export function withoutAbortController(a: number, b: number): Promise<number>
export function withAbortController(a: number, b: number, ctrl: AbortController): Promise<number>
export function withAbortController(a: number, b: number, signal: AbortSignal): Promise<number>
export function getBuffer(): Buffer
export class Animal {
readonly kind: Kind

View file

@ -5,17 +5,17 @@ use napi::Task;
struct DelaySum(u32, u32);
#[napi]
#[napi(task)]
impl Task for DelaySum {
type Output = u32;
type JsValue = u32;
fn compute(&mut self) -> Result<Self::Output> {
sleep(std::time::Duration::from_secs(1));
sleep(std::time::Duration::from_millis(100));
Ok(self.0 + self.1)
}
fn resolve(self, _env: napi::Env, output: Self::Output) -> Result<Self::JsValue> {
fn resolve(&mut self, _env: napi::Env, output: Self::Output) -> Result<Self::JsValue> {
Ok(output)
}
}
@ -26,6 +26,6 @@ fn without_abort_controller(a: u32, b: u32) -> AsyncTask<DelaySum> {
}
#[napi]
fn with_abort_controller(a: u32, b: u32, ctrl: AsyncTaskAbortController) -> AsyncTask<DelaySum> {
AsyncTask::with_abort_controller(DelaySum(a, b), ctrl)
fn with_abort_controller(a: u32, b: u32, signal: AbortSignal) -> AsyncTask<DelaySum> {
AsyncTask::with_signal(DelaySum(a, b), signal)
}