Introduction
这里的 异常处理 指的是 node-addon-api 如何在 C++ 与 JavaScript 之间进行异常的交互,可以分为:
- C++ 中向 JavaScript 抛出一个异常,异常应由 JavaScript 捕获或者继续冒泡
- C++ 中调用 JavaScript 函数时怎么处理 JavaScript 函数抛出的 JavaScript 异常
- 直接处理 JavaScript 异常
- 向外冒泡异常(将异常再次抛给 JavaScript)
整体上,node-addon-api 提供了两种方式用于解决 C++ 和 JavaScript 之间的异常交互问题。
启用 C++ 异常处理机制时,C++ 可以通过 throw 关键字向 JavaScript 抛出一个异常,通过 try/catch 捕获 JavaScript 函数抛出的异常。
这里涉及到了两种异常对象(JavaScript 异常和 C++ Napi::Error
异常)之间的转换问题,这种转换是自动进行的。
禁用 C++ 异常处理机制时,C++ 不能通过 throw 向 JavaScript 抛出异常了,也不能通过 try/catch 捕获 JavaScript 函数抛出的异常。
注意,是不能使用 throw / try / catch 处理 C++ 和 JavaScript 之间的异常交互,对 C++ 内部的异常处理没有影响。
此时,node-addon-api 通过将异常信息保存在返回值中返回给 JavaScript,或者通过检测 env 对象的异常状态来判断执行 JavaScript 函数时是否发生异常。
上述异常处理机制又涉及到两种方式:基于Value
对象的,和将返回的Value
对象打包成Maybe
对象的检测。
综上,node-addon-api 处理 C++ 和 JavaScript 异常交互的方式有:
- 启用 C++ 异常时:throw / try / catch
- 禁用 C++ 异常时:returned
Value
object- check
Value
value - check
Maybe
value (boxedValue
value)
- check
下面分别举例:
Enable C++ exceptions
此时Napi::Error
类将从std::exception
继承。
向 JavaScript 抛出异常
与一般异常处理逻辑相同,通过 throw 关键字抛出异常:
throw Error::New(env, "error message");
处理 JavaScript 函数抛出的异常
C++ 中调用 JavaScript 函数,函数执行过程中可能会抛出异常。
与一般异常处理逻辑相同,通过 try/catch 处理异常,JavaScript 函数抛出的异常会被自动转换成Error
对象。
// 执行 js 函数前需要先将其转换为 Function 对象
Function jsFunc = someValue.As<Function>();
try {
Value result = jsFunc({ arg1, arg2 });
} catch (const Error& e) {
// 通过`Error`对象的`what()`方法获取异常消息
cerr << "JavaScript exception: " + e.what();
}
抛出 JavaScript 函数抛出的异常
如果需要将 JavaScript 函数抛出的异常重新抛回给 JavaScript,那么啥也不需要做,异常会自己冒泡:
Value result = jsFunc({ arg1, arg2 });
Disable C++ exceptions
此时,Napi::Error
不会从std::excaption
继承。
不能使用 throw 向 JavaScript 抛出异常,也不能通过 try/catch 捕获 JavaScript 抛出的异常。
向 JavaScript 抛出异常
node-addon-api 为Error
对象实现了一个ThrowAsJavaScriptException()
方法用于直接向 JavaScript 抛出异常:
Error::New(env, "error message").ThrowAsJavaScriptException();
处理 JavaScript 函数抛出的异常
node-addon-api 通过检测 JavaScript 函数的返回值或者环境对象来判断 JavaScript 函数执行是否发生异常。
检测 Value 对象
默认情况下,JavaScript 函数执行结束后返回一个Value
实例:
Value result = jsFunc();
通过env.IsExceptionPending()
可以检测 JavaScript 函数执行过程中是否发生异常。
通过env.GetAndClearPendingException()
取回异常对象并重置全局异常记录变量的状态。
// JavaScript 函数抛出了异常
if (env.IsExceptionPending()) {
Error e = env.GetAndClearPendingException();
cerr << "JavaScript exception: " + e.what();
}
检测 Maybe 对象
Maybe
是对基于返回值进行异常检测的简单包装。
Maybe<Value> maybeResult = jsFunc();
if (maybeResult.IsNothing()) {
Error e = env.GetAndClearPendingException();
cerr << "JavaScript exception: " + e.what();
}
抛出 JavaScript 函数抛出的异常
与直接处理异常类似。
检测 Value 对象
需要从环境对象中取回并重置异常,然后返回异常的内容。
实际上是将异常当做返回值在处理。
Value v = jsFunc();
if (v.IsExceptionPending()) {
Error e = env.GetAndClearPendingException();
return e.Value();
}
检测 Maybe 对象
相对于检测Value
实例来说,更加简洁。
Maybe<Value> mv = jsFunc();
Value v;
if (!mv.To(&v)) {
return v;
}
Macros
node-addon-api 提供了几个宏用于抛出异常,开发者不需要关系 C++ 异常机制是否被禁用了。
NAPI_THROW(error, ...)
抛出一个 Error 对象,同时返回一个值。如果启用了 C++ 异常,返回的值会被忽略。
NAPI_THROW_IF_FAILED(env, status, ...)
指定一个 napi_status 自动构建一个 Error 对象,同时返回一个值。如果启用了 C++ 异常,返回的值会被忽略。
NAPI_THROW_IF_FAILED_VOID(env, status)
指定一个 napi_status 自动构建一个 Error 对象,同时返回。如果启用了 C++ 异常,返回的值会被忽略。
NAPI_FATAL_IF_FAILED(status, location, message)
指定一个 napi_status,一个字符串表示出错的位置,一个展示错误消息的字符串。
评论区