|
| 1 | +# `tokio-fetch` |
| 2 | + |
| 3 | +Example of spawning a Rust async task on the [tokio][tokio] thread pool and resolving a JavaScript [Promise][promise] after it completes. |
| 4 | + |
| 5 | +_**Note:** This example uses a pre-release version of Neon._ |
| 6 | + |
| 7 | +[tokio]: https://tokio.rs |
| 8 | +[promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise |
| 9 | + |
| 10 | +## Methods |
| 11 | + |
| 12 | +#### `function nodeReleaseDate(): Promise<string>` |
| 13 | + |
| 14 | +Asynchronously fetch the release date for the currently running Node process from nodejs.org. |
| 15 | + |
| 16 | +## Design |
| 17 | + |
| 18 | +### Executor |
| 19 | + |
| 20 | +For optimum task scheduling, it is best to have a single Rust task executor (e.g., tokio runtime). To make the runtime singleton available to Neon functions, it is stored in a global using `OnceCell`. |
| 21 | + |
| 22 | +```rust |
| 23 | +use once_cell::sync::OnceCell; |
| 24 | +use tokio::runtime::Runtime; |
| 25 | + |
| 26 | +static RUNTIME: OnceCell<Runtime> = OnceCell::new(); |
| 27 | +``` |
| 28 | + |
| 29 | +A small helper is provided to lazily initialize the runtime and throw an exception on failure. |
| 30 | + |
| 31 | +```rust |
| 32 | +fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> { |
| 33 | + RUNTIME.get_or_try_init(|| Runtime::new().or_else(|err| cx.throw_error(err.to_string()))) |
| 34 | +} |
| 35 | +``` |
| 36 | + |
| 37 | +### Spawning Tasks |
| 38 | + |
| 39 | +Tasks may be spawned on the tokio runtime by using the `RUNTIME` handle. Spawning a task does *not* block the current thread. Inside a task the `await` keyword may be used and typical async Rust patterns may be used. |
| 40 | + |
| 41 | +```rust |
| 42 | +let rt = runtime(&mut cx)?; |
| 43 | + |
| 44 | +rt.spawn(async move { |
| 45 | + // Asynchronous Rust may used in here |
| 46 | +}); |
| 47 | +``` |
| 48 | + |
| 49 | +### Promises |
| 50 | + |
| 51 | +When a task is spawned on the tokio runtime, it will be executed at a later time. JavaScript needs to be notified when the task completes. |
| 52 | + |
| 53 | +* Neon [`Channel`][channel] may be created for moving an operation from the tokio thread pool back to the JavaScript main thread. |
| 54 | +* [`cx.promise()`][cx-promise] creates a [`JsPromise`][js-promise] and [`Deferred`][deferred] for signaling JavaScript. |
| 55 | +* [`JsPromise`][js-promise] is synchronously returned and may be used with `await` in JavaScript |
| 56 | +* [`Deferred`][deferred] is used to settle the [`JsPromise`][js-promise] from the [`Channel`][channel] callback. |
| 57 | + |
| 58 | +```rust |
| 59 | +let channel = cx.channel(); |
| 60 | +let (deferred, promise) = cx.promise(); |
| 61 | + |
| 62 | +rt.spawn(async move { |
| 63 | + // Code here executes non-blocking on the tokio thread pool |
| 64 | + |
| 65 | + deferred.settle_with(&channel, move |mut cx| { |
| 66 | + // Code here executes blocking on the JavaScript main thread |
| 67 | + |
| 68 | + Ok(cx.undefined()) |
| 69 | + }); |
| 70 | +}); |
| 71 | + |
| 72 | +Ok(promise) |
| 73 | +``` |
| 74 | + |
| 75 | +[channel]: https://docs.rs/neon/0.10.0-alpha.3/neon/event/struct.Channel.html |
| 76 | +[cx-promise]: https://docs.rs/neon/0.10.0-alpha.3/neon/context/trait.Context.html#method.promise |
| 77 | +[js-promise]: https://docs.rs/neon/0.10.0-alpha.3/neon/types/struct.JsPromise.html |
| 78 | +[deferred]: https://docs.rs/neon/0.10.0-alpha.3/neon/types/struct.Deferred.html |
0 commit comments