Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async worker and error handling documentation #272

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ values. Concepts and operations generally map to ideas specified in the
- [PropertyDescriptor](doc/property_descriptor.md)
- [Error Handling](doc/error_handling.md)
- [Error](doc/error.md)
- [TypeError](doc/type_error.md)
- [RangeError](doc/range_error.md)
- [Object Lifettime Management](doc/object_lifetime_management.md)
- [HandleScope](doc/handle_scope.md)
- [EscapableHandleScope](doc/escapable_handle_scope.md)
Expand Down
26 changes: 23 additions & 3 deletions doc/async_operations.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Asynchronous operations

You are reading a draft of the next documentation and it's in continuos update so
if you don't find what you need please refer to:
[C++ wrapper classes for the ABI-stable C APIs for Node.js](https://nodejs.github.io/node-addon-api/)
Node.js native add-ons often need to execute long running tasks and to avoid of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove of

blocking the **event loop** they have to accomplish to them in the asynchronous way.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have to accomplish to them -> have to run them asynchronously from the event loop.

Lets do a quick overview of how asynchronous code work in Node.js. In our model
Copy link
Member

@mhdawson mhdawson May 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would drop the sentence Lets ... Node.js and change In our model to be `In the Node.js model'

of execution we have **two threads**, the first is the **event loop** thread, that
Copy link
Member

@mhdawson mhdawson May 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'we have' -> 'there are', the node.js guidance is to avoid you, we etc.

represents the thread where or JavaScript code is executing in. We want avoid to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove 'or' and 'in'

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want avoid to -> In order to avoid

stall the event loop thread doing heavy computation so we need to create a sencond
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'stalling the event loop thread' -> blocking other work queued on the event loop by. Therefore, we need to do this work on another thread.

thread called **worker thread** managed by **libuv**, the libary that supports the
asynchronous I/O in Node.js.

All this means that native add-ons need to leverage async helpers from libuv as
part of their implementation. This allows them to schedule work to be executed
asynchronously so that their methods can return in advance of the work being
completed.

Node Addon API provides an ABI-stable interface to support functions which covers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"which coversthat cover"

the most common asynchronous use cases. You have two abstract class to implement
Copy link
Contributor

@gabrielschulhof gabrielschulhof Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The general guidance is to not formulate sentences using "you". So, we should have "You haveThere are".

"abstract classes"

asynchronous operation:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"operations"


- **[AsyncWorker](async_worker.md)**
- **[Async Context](async_context.md)**

These two classes help you to manage asynchronous operations through an abstraction
Copy link
Contributor

@gabrielschulhof gabrielschulhof Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"help you to"

of the concept of moving data between the **event loop** and **worker threads**.
195 changes: 191 additions & 4 deletions doc/async_worker.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,192 @@
# Async worker
# AsyncWorker
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you say more about the lifetime of the AsyncWorker? I may have missed it, but I'm trying to understand exactly when/how the AsyncWorker is destroyed. I have an issue currently where Jest never exits and the uv loop has a handle count of 1. I don't know what that object is, it could be something I did in JavaScript, but the AsyncWorker I created is a suspicious candidate.


You are reading a draft of the next documentation and it's in continuos update so
if you don't find what you need please refer to:
[C++ wrapper classes for the ABI-stable C APIs for Node.js](https://nodejs.github.io/node-addon-api/)
`AsyncWorker` is an abstract class that you can subclass to remove much of the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"muchmany"

tedious tasks on moving data between the event loop and worker threads. This
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"onof"

class internally handles all the details of creating and executing asynchronous
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"an asynchronous"

operation.

## Methods

### Env

Requests the environment in which the async worker has been initially created.

```cpp
Env Env() const;
```

Returns the environment in which the async worker has been created.

### Queue

Requests that the created work or task will be placed on the queue of the execution.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps instead of "placed on the queue of the execution" we could say "queued for execution".


```cpp
void Queue();
```

### Cancel

Cancels queued work if it has not yet been started. If it has already started
executing, it cannot be cancelled.

```cpp
void Cancel();
```

### Receiver

```cpp
ObjectReference& Receiver();
```

Returns the persistent object reference of the receiver objet set when the async
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"object"

worker is created.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"iswas"


### Callback

```cpp
FunctionReference& Callback();
```

Returns the persistent function reference of the callback set when the async
worker is created. The returned function reference will be called passing it the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"iswas"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe "will be called passing itreceive"

results of the computation happened on the `Execute` method.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"computation that happened onin"


### SetError

Sets the error message for the error happened during the execution.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"error that happened"


```cpp
void SetError(const std::string& error);
```

- `[in] error`: The reference to string that represent the message of the error.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"to the string"



### Execute

This method is used to execute some tasks out of the **event loop** on a libuv
worker thread.

```cpp
virtual void Execute() = 0;
```

### OnOK

This method represents a callback that is invoked when the computation on the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"onin"

`Excecute` method end.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"ends"


```cpp
virtual void OnOK();
```

### OnError

```cpp
virtual void OnError(const Error& e);
```

### Constructor

Creates new async worker
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Create a new async worker ." (period at the end of the sentence)


```cpp
explicit AsyncWorker(const Function& callback);
```

### Constructor

Creates new async worker
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto


```cpp
explicit AsyncWorker(const Object& receiver, const Function& callback);
```

### Destructor

Deletes the created work object that is used to execute logic asynchronously
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A period is missing from the end of the sentence.


```cpp
virtual ~AsyncWorker();
```

## Operator

```cpp
operator napi_async_work() const;
```

Returns the N-API napi_async_work wrapped by the AsyncWorker object. This can be
used to mix usage of the C N-API and node-addon-api.

## Example

The first step to use `AsyncWorker` class is to create a new class that inherit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"to use the `AsyncWorker` class is to create a new class that inherits"

from it and implement the `Execute` abstract method. Typically input to your
worker will be saved within your fields' class generally passed in through its
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"fields' classclass' fields" or "the fields of your class"

constructor.

When the `Execute` method complete without errors the `OnOK` function callback
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"completes"

will be invoked. In this function the results of the computation will be
reassembled and returned back to initial JavaScript context.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"to the initial"


`AsyncWorker` ensure that all the code inside in the `Execute` function runs in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"inside"

background out of the **event loop** thread and at the end `OnOK` or `OnError`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"the background"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"at the end the"

function will be called and are executed as part of the event loop.

The code below show a basic example of `AsyncWorker` implementation:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"shows a basic example of the"


```cpp
#include<napi.h>

#include <chrono>
#include <thread>

use namespace Napi;

class EchoWorker : public AsyncWorker {
public:
EchoWorker(Function& callback, std::string& echo)
: AsyncWorker(callback), echo(echo) {}

~EchoWorker() {}
// This code will be executed on the worker thread
void Execute() {
// Need to simulate cpu heavy task
std::this_thread::sleep_for(std::chrono::seconds(1));
}

void OnOK() {
HandleScope scope(Env());
Callback().Call({Env().Null(), String::New(Env(), echo)});
}

private:
std::string echo;
};
```

The `EchoWorker`'s contructor call the base class's constructor to pass in the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"calls the base class's"

callback that the `AsyncWorker` base class will store persistently. When the work
on the `Execute` method is done the `OnOk` method is called and the results return
back to JavaScript invoking the stored callback with its associated environment.

The following code show an example on how to create and and use an `AsyncWorker`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"shows"


```cpp
Value Echo(const CallbackInfo& info) {
// You need to check the input data here
Function cb = info[1].As<Function>();
std::string in = info[0].As<String>();
EchoWorker* wk = new EchoWorker(cb, in);
wk->Queue();
return info.Env().Undefined();
```

Use the implementation of an `AsyncWorker` is very simple you need only to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Useing the implementation" ... "is very simple⁠. Yyou need only to"

create a new instance and pass to its constructor the callback you want exectute
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"want to exectute"

when your asynchronous task end and other data you need for your computation. The
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"task ends"

Not sure how this part of the sentence fits with the first part above.

only action you have to do is to call the `Queue` method that will place the
crearted worker on the queue of the execution.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should say "that will queue the created worker for execution".

102 changes: 99 additions & 3 deletions doc/error.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,101 @@
# Error

You are reading a draft of the next documentation and it's in continuos update so
if you don't find what you need please refer to:
[C++ wrapper classes for the ABI-stable C APIs for Node.js](https://nodejs.github.io/node-addon-api/)
The **Error** class is a representation of the JavaScript Error object that is thrown
when runtime errors occur. The Error object can also be used as a base object for
user defined exceptions.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"user-defined" (with a dash)


The **Error** class is a persistent reference to a JavaScript error object and
inherits its behaviour from ObjectReference class (for more info see: [ObjectReference](object_reference.md)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"thus inherits its behaviour from the ` ObjectReference ` class"

section).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need "section" here.


If C++ exceptions are enabled (for more info see: [Setup](setup.md) section),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"section"

then the **Error** class extends ```std::exception``` and enables integrated
error-handling for C++ exceptions and JavaScript exceptions.

For more details about error handling refer to the section titled [Error handling](error_handling.md).

## Methods

### New

Creates a new instance empty of ```Error``` object for the specified environment.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"instance emptyempty instance of an"

Also, I believe one backtick is enough when writing inline.


```cpp
Error::New(Napi:Env env);
```

- ```[in] Env```: The environment in which to construct the Error object.

Returns an instance of ```Error``` object.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"instance of an"


### New

Creates a new instance of ```Error``` object
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"instance of an"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Period at the end.


```cpp
Error::New(Napi:Env env, const char* message);
```

- ```[in] Env```: The environment in which to construct the Error object.
- ```[in] message```: Null-terminated strings to be used as the message for the Error.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"strings" ... "` Error ` "


Returns an instance of ```Error``` object.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"instance of an"


### New

Creates a new instance of ```Error``` object
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"instance of an" ... and only one backtick around Error.


```cpp
Error::New(Napi:Env env, const std::string& message);
```

- `[in] Env`: The environment in which to construct the Error object.
- `[in] message`: Reference string to be used as the message for the Error.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backticks around Error.


Returns an instance of ```Error``` object.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"instance of an" and only one backtick.


### Constructor

Creates a new empty instance of ```Error```
Copy link
Contributor

@gabrielschulhof gabrielschulhof Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only one backtick and period at the end of the sentence.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, inline code snippets need only one backtick.


```cpp
Error();
```

### Constructor

Initializes a ```Error``` instance from an existing ```Error``` object.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"an"


```cpp
TypeError(napi_env env, napi_value value);
```

- ```[in] Env```: The environment in which to construct the Error object.
- ```[in] value```: The ```Error``` reference to wrap.

Returns an instance of ```Error``` object.

### Message

```cpp
std::string& Message() const NAPI_NOEXCEPT;
```

Returns the reference to string that represent the message of the error.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"to the string"


### ThrowAsJavaScriptException

```cpp
void ThrowAsJavaScriptException() const;
```

Throw the error as JavaScript exception.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"as a JavaScript"


### what

```cpp
const char* what() const NAPI_NOEXCEPT override;
```

Returns a pointer to a null-terminated string that is used to identify the
exception. This method can be used only if the eceptions mechanis is enabled.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"mechanism"

Loading