如何从 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::Valuev8::Local<v8::Value>v8::MaybeLocal<v8::Value>, 和 v8::Local<v8::BigInt> 是有意义的,当你不只是将它们隐藏在 auto 后面时,它可以帮助你编写正确的代码。)