как получить возвращаемое значение функции JS из V8? - PullRequest
0 голосов
/ 06 мая 2020

Сейчас я пытаюсь получить возвращаемое значение функции, которую я вызываю в 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. Что я делаю не так?

Спасибо

Тобиас

1 Ответ

1 голос
/ 06 мая 2020

Как сказано в документации, v8::Value::IntegerValue() «Возвращает эквивалент ToInteger()->Value()», что означает, что он генерирует исключение (т.е. возвращает Nothing) при вызове BigInt, отражая тот факт, что в JavaScript , вызывая «абстрактную операцию» ToInteger() на BigInt, выдает TypeError, или другими словами: BigInt не просто неявно конвертируется в Number.

Чтобы извлечь значение BigInt из C ++, вы можете сделать следующее:

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

Конечно, это даст неверный результат, если значение BigInt больше, чем int64. Требуется необязательный bool*, чтобы указать, было ли преобразование в int64 без потерь или с усечением. Если вам нужно получить большие значения, вы можете использовать метод ToWordsArray(...).

как получить возвращаемое значение функции JS из V8?

Точно так же, как и вы:

v8::MaybeLocal<v8::Value> result = func->Call(...);

Обратите внимание, что использование .ToLocalChecked(); рискованно: если функция генерирует исключение вместо возврата значения, тогда .ToLocalChecked() выдаст ошибку sh. Если вы не контролируете код функции и, следовательно, не можете гарантировать, что она не сработает, тогда лучше проверить, является ли результат пустым, и аккуратно обработать исключения. См. Каталог V8 samples/ или документацию v8.dev / docs / , где можно найти множество примеров и дополнительных объяснений.

(Примечание: я бы рекомендовал использовать auto намного меньше. Это помогает увидеть типы. Различия, скажем, между v8::Value, v8::Local<v8::Value>, v8::MaybeLocal<v8::Value> и v8::Local<v8::BigInt> значительны, и это помогает вам писать правильный код, когда вы не просто скрываете их сзади auto.)

...