如何从 V8 获取 JS 函数的 return 值?
how to get the return value of a JS function from V8?
我目前正在尝试获取我在 JS 中调用的函数的 return 值。下面的代码可以重现它(减去 v8 包含)
#include "v8.h"
#include "libplatform/libplatform.h"
#include <string>
#include <cassert>
int64_t repro()
{
auto isolate = v8::Isolate::New(initializer.create_params_);
assert(isolate != nullptr);
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
auto context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
assert(context.IsEmpty() == false);
auto global = context->Global();
std::string script = "function foo() {\n"
" return BigInt(1);\n"
"}";
v8::Local<v8::String> sourceScript =
v8::String::NewFromUtf8(isolate, script.c_str(),
v8::NewStringType::kNormal)
.ToLocalChecked();
v8::Local<v8::Script> s =
v8::Script::Compile(context, sourceScript).ToLocalChecked();
s->Run(context);
v8::Local<v8::String> name =
v8::String::NewFromUtf8(isolate, "foo",
v8::NewStringType::kInternalized)
.ToLocalChecked();
auto value = global->Get(context, name).ToLocalChecked();
assert(value->IsFunction());
auto func = v8::Handle<v8::Function>::Cast(value);
auto result = func->Call(context, context->Global(), 0, nullptr)
.ToLocalChecked();
assert(result->IsBigInt());
auto bigint = result->IntegerValue(context);
assert(bigint.IsNothing() == false);
return bigint.ToChecked();
}
当我现在查看 bigint 时 - 类型报告为 BigInt,但 IsNothing() return 是正确的。我做错了什么?
谢谢
托比亚斯
如文档所述,v8::Value::IntegerValue()
"Returns the equivalent of ToInteger()->Value()
",这意味着它在 BigInt
上调用时抛出异常(即 returns Nothing
),反映了在 JavaScript 中调用 "abstract operation" ToInteger()
对 BigInt
抛出 TypeError
的事实,换句话说:BigInt
不会' 只是隐式转换为 Number
。
要从 C++ 中提取 BigInt
的值,您可以这样做:
int64_t bigint = v8::Local<v8::BigInt>::cast(result)->Int64Value();
当 BigInt 的值大于 int64 时,当然会给出不正确的结果。它需要一个可选的 bool*
来指示到 int64 的转换是无损的还是截断的。如果您需要获得更大的值,可以使用 ToWordsArray(...)
方法。
how to get the return value of a JS function from V8?
和你一样:
v8::MaybeLocal<v8::Value> result = func->Call(...);
请注意,使用 .ToLocalChecked();
是有风险的:如果函数抛出异常而不是返回值,那么 .ToLocalChecked()
将崩溃。如果你不控制函数的代码,不能保证它不会抛出,那么最好测试结果是否为空,优雅地处理异常。请参阅 V8 的 samples/
目录或 v8.dev/docs/ 上的文档,以获取大量示例和其他解释。
(旁注:我建议少用 auto
。它有助于查看类型。例如,v8::Value
、v8::Local<v8::Value>
、v8::MaybeLocal<v8::Value>
, 和 v8::Local<v8::BigInt>
是有意义的,当你不只是将它们隐藏在 auto
后面时,它可以帮助你编写正确的代码。)
我目前正在尝试获取我在 JS 中调用的函数的 return 值。下面的代码可以重现它(减去 v8 包含)
#include "v8.h"
#include "libplatform/libplatform.h"
#include <string>
#include <cassert>
int64_t repro()
{
auto isolate = v8::Isolate::New(initializer.create_params_);
assert(isolate != nullptr);
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
auto context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
assert(context.IsEmpty() == false);
auto global = context->Global();
std::string script = "function foo() {\n"
" return BigInt(1);\n"
"}";
v8::Local<v8::String> sourceScript =
v8::String::NewFromUtf8(isolate, script.c_str(),
v8::NewStringType::kNormal)
.ToLocalChecked();
v8::Local<v8::Script> s =
v8::Script::Compile(context, sourceScript).ToLocalChecked();
s->Run(context);
v8::Local<v8::String> name =
v8::String::NewFromUtf8(isolate, "foo",
v8::NewStringType::kInternalized)
.ToLocalChecked();
auto value = global->Get(context, name).ToLocalChecked();
assert(value->IsFunction());
auto func = v8::Handle<v8::Function>::Cast(value);
auto result = func->Call(context, context->Global(), 0, nullptr)
.ToLocalChecked();
assert(result->IsBigInt());
auto bigint = result->IntegerValue(context);
assert(bigint.IsNothing() == false);
return bigint.ToChecked();
}
当我现在查看 bigint 时 - 类型报告为 BigInt,但 IsNothing() return 是正确的。我做错了什么?
谢谢
托比亚斯
如文档所述,v8::Value::IntegerValue()
"Returns the equivalent of ToInteger()->Value()
",这意味着它在 BigInt
上调用时抛出异常(即 returns Nothing
),反映了在 JavaScript 中调用 "abstract operation" ToInteger()
对 BigInt
抛出 TypeError
的事实,换句话说:BigInt
不会' 只是隐式转换为 Number
。
要从 C++ 中提取 BigInt
的值,您可以这样做:
int64_t bigint = v8::Local<v8::BigInt>::cast(result)->Int64Value();
当 BigInt 的值大于 int64 时,当然会给出不正确的结果。它需要一个可选的 bool*
来指示到 int64 的转换是无损的还是截断的。如果您需要获得更大的值,可以使用 ToWordsArray(...)
方法。
how to get the return value of a JS function from V8?
和你一样:
v8::MaybeLocal<v8::Value> result = func->Call(...);
请注意,使用 .ToLocalChecked();
是有风险的:如果函数抛出异常而不是返回值,那么 .ToLocalChecked()
将崩溃。如果你不控制函数的代码,不能保证它不会抛出,那么最好测试结果是否为空,优雅地处理异常。请参阅 V8 的 samples/
目录或 v8.dev/docs/ 上的文档,以获取大量示例和其他解释。
(旁注:我建议少用 auto
。它有助于查看类型。例如,v8::Value
、v8::Local<v8::Value>
、v8::MaybeLocal<v8::Value>
, 和 v8::Local<v8::BigInt>
是有意义的,当你不只是将它们隐藏在 auto
后面时,它可以帮助你编写正确的代码。)