V8 使用已弃用的 v8::Local<v8::Value> v8::Object::Get(v8::Local<v8::Value>) 更新代码?

V8 updating code using deprecated v8::Local<v8::Value> v8::Object::Get(v8::Local<v8::Value>)?

由于 NodeJS 14 的损坏,我正在更新 NodeJS package。该库使用 C++ 代码。在 NodeJS 12 中,相同的代码显示为弃用警告:

warning: ‘v8::Local<v8::Value> v8::Object::Get(v8::Local<v8::Value>)’ is deprecated: Use maybe version

有问题的代码是:

v8::Local<v8::Object> options = v8::Local<v8::Object>::Cast(info[0]);
v8::Local<v8::Value> debug = options->Get(Nan::New<v8::String>("debug").ToLocalChecked());

if (true) {
    v8::Local<v8::Value> leds = options->Get(Nan::New<v8::String>("leds").ToLocalChecked());

    if (!leds->IsUndefined())
        ws2811.channel[0].count = Nan::To<int>(leds).FromMaybe(ws2811.channel[0].count);
    else
        return Nan::ThrowTypeError("configure(): leds must be defined");
}

我确实尝试了以下方法,虽然它确实编译了,但运行时提示这可能是错误的,因为我遇到了在此代码更改之前不存在的失败:

v8::Local<v8::Object> options = v8::Local<v8::Object>::Cast(info[0]);
Nan::MaybeLocal<v8::Value> debug = Nan::Get(options, Nan::New<v8::String>("debug").ToLocalChecked());

if (true) {
    Nan::MaybeLocal<v8::Value> maybe_leds = Nan::Get(options, Nan::New<v8::String>("leds").ToLocalChecked());
    v8::Local<v8::Value> leds;

    if (!maybe_leds.IsEmpty() && maybe_leds.ToLocal(&leds))
        ws2811.channel[0].count = Nan::To<int>(leds).FromMaybe(ws2811.channel[0].count);
    else
        return Nan::ThrowTypeError("configure(): leds must be defined");
}

我对 C++ 很生疏,对 V8 还很陌生,在这种情况下,我有点困惑 Get 方法的正确替代方法是什么。我认为我理解的是我们需要使用 MaybeLocal 而不是 Local。进行搜索发现很多其他人也有类似的问题,但没有任何我可以用作解决方案的东西。

顺便说一句,这个项目确实依赖于 nan

经过更多挖掘,这似乎是正确的方法。这基本上是根据我在网上找到的 Nan 文档和片段拼凑而成的:

v8::Local<v8::Object> options = v8::Local<v8::Object>::Cast(info[0]);
v8::MaybeLocal<v8::Value> debug = Nan::Get(options, Nan::New<v8::String>("debug").ToLocalChecked());

if (Nan::Has(options, Nan::New<v8::String>("leds").ToLocalChecked()).ToChecked()) {
    Nan::MaybeLocal<v8::Value> maybe_leds = Nan::Get(options, Nan::New<v8::String>("leds").ToLocalChecked());
    v8::Local<v8::Value> leds;

    if (maybe_leds.ToLocal(&leds))
        ws2811.channel[0].count = Nan::To<int>(leds).FromMaybe(ws2811.channel[0].count);
    else
        return Nan::ThrowTypeError("configure(): leds must be defined");
}

看来 Nan::Has 检查很重要,否则代码似乎无法正常运行。

关键的见解是涉及 JavaScript 的大多数操作都可以抛出异常而不是返回值。 MaybeLocal 约定明确说明了这一点:MaybeLocal 要么是 Local(如果 function/operation 返回了一个值),要么是空的(如果有异常)。如果你有 v8::TryCatchNan::TryCatch,它会捕获后一种情况下的异常。

嵌入代码处理MaybeLocals的方式有多种;最优雅的是 bool-返回 .ToLocal(...) 方法。相当于检查.IsEmpty(),所以你不需要两者都做。

所以这会给你:

Nan::TryCatch try_catch;
v8::Local<v8::String> leds_string = Nan::New<v8::String>("leds").ToLocalChecked();
Nan::MaybeLocal<v8::Value> maybe_leds = Nan::Get(options, leds_string);

v8::Local<v8::Value> leds;
if (!maybe_leds.ToLocal(&leds)) {
  // An exception was thrown while reading `options["leds"]`.
  // This is the same as `maybe_leds.IsEmpty() == true`.
  // It is also the same as `try_catch.HasCaught() == true`.
  return try_catch.ReThrow();
}
// Now follows your original code.
if (leds->IsUndefined()) {
  // The `options` object didn't have a `leds` property, or it was undefined.
  return Nan::ThrowTypeError("configure(): leds must be defined");
}

// Success case: all good.
ws2811.channel[0].count = Nan::To<int>(leds).FromMaybe(ws2811.channel[0].count);

请参阅 https://github.com/nodejs/nan/blob/master/doc/maybe_types.md 处的文档。