如何从V8获取JS函数的返回值?

时间:2020-05-05 21:34:57

标签: v8 embedded-v8

我目前正在尝试获取我在JS中调用的函数的返回值。以下代码可以重现(减去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()返回true。我在做什么错了?

谢谢

Tobias

1 个答案:

答案 0 :(得分:2)

如文档所述,v8::Value::IntegerValue()“返回等效的ToInteger()->Value()”,这意味着在Nothing上调用它会引发异常(即返回BigInt),反映出以下事实:在JavaScript中,在BigInt上调用“抽象操作” ToInteger()会抛出TypeError,或者换句话说:BigInt并不只是隐式转换到Number

要从C ++中提取BigInt的值,可以执行以下操作:

int64_t bigint = v8::Local<v8::BigInt>::cast(result)->Int64Value();

当然,当BigInt的值大于int64时,将给出错误的结果。它需要一个可选的bool*来指示到int64的转换是无损的还是被截断的。如果需要更大的值,可以使用ToWordsArray(...)方法。

如何从V8获取JS函数的返回值?

与您完全一样:

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后面时,它可以帮助您编写正确的代码。