doc: suggest not to throw JS errors from C++

Also provide an example on how to use internal/errors
to handle errors in C++.

PR-URL: https://github.com/nodejs/node/pull/18149
Refs: https://github.com/nodejs/node/issues/18106
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Jon Moss <me@jonathanmoss.me>
Reviewed-By: Weijia Wang <starkwang@126.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
This commit is contained in:
Joyee Cheung 2018-01-15 02:51:36 +08:00 committed by Myles Borins
parent 80973ec6c3
commit afc528920b
No known key found for this signature in database
GPG Key ID: 933B01F40B5CA946

View File

@ -20,7 +20,8 @@
* [Others](#others)
* [Type casting](#type-casting)
* [Do not include `*.h` if `*-inl.h` has already been included](#do-not-include-h-if--inlh-has-already-been-included)
* [Avoid throwing JavaScript errors in nested C++ methods](#avoid-throwing-javascript-errors-in-nested-c-methods)
* [Avoid throwing JavaScript errors in C++ methods](#avoid-throwing-javascript-errors-in-c)
* [Avoid throwing JavaScript errors in nested C++ methods](#avoid-throwing-javascript-errors-in-nested-c-methods)
Unfortunately, the C++ linter (based on
[Googles `cpplint`](https://github.com/google/styleguide)), which can be run
@ -213,12 +214,65 @@ instead of
#include "util-inl.h"
```
## Avoid throwing JavaScript errors in nested C++ methods
## Avoid throwing JavaScript errors in C++
If you need to throw JavaScript errors from a C++ binding method, try to do it
at the top level and not inside of nested calls.
When there is a need to throw errors from a C++ binding method, try to
return the data necessary for constructing the errors to JavaScript,
then construct and throw the errors [using `lib/internal/errors.js`][errors].
A lot of code inside Node.js is written so that typechecking etc. is performed
in JavaScript.
Note that in general, type-checks on arguments should be done in JavaScript
before the arguments are passed into C++. Then in the C++ binding, simply using
`CHECK` assertions to guard against invalid arguments should be enough.
If the return value of the binding cannot be used to signal failures or return
the necessary data for constructing errors in JavaScript, pass a context object
to the binding and put the necessary data inside in C++. For example:
```cpp
void Foo(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
// Let the JavaScript handle the actual type-checking,
// only assertions are placed in C++
CHECK_EQ(args.Length(), 2);
CHECK(args[0]->IsString());
CHECK(args[1]->IsObject());
int err = DoSomethingWith(args[0].As<String>());
if (err) {
// Put the data inside the error context
Local<Object> ctx = args[1].As<Object>();
Local<String> key = FIXED_ONE_BYTE_STRING(env->isolate(), "code");
ctx->Set(env->context(), key, err).FromJust();
} else {
args.GetReturnValue().Set(something_to_return);
}
}
// In the initialize function
env->SetMethod(target, "foo", Foo);
```
```js
exports.foo = function(str) {
// Prefer doing the type-checks in JavaScript
if (typeof str !== 'string') {
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'str', 'string');
}
const ctx = {};
const result = binding.foo(str, ctx);
if (ctx.code !== undefined) {
throw new errors.Error('ERR_ERROR_NAME', ctx.code);
}
return result;
};
```
### Avoid throwing JavaScript errors in nested C++ methods
When you have to throw the errors from C++, try to do it at the top level and
not inside of nested calls.
Using C++ `throw` is not allowed.
[errors]: https://github.com/nodejs/node/blob/master/doc/guides/using-internal-errors.md