JavaScript生成器函数--用C++编写

3

如何使用V8 C++ API在Javascript中实现生成器接口?我想创建一个可以用作for-of循环的迭代器对象。


嗯,祝你好运处理那种“规范问题”。 - πάντα ῥεῖ
1个回答

1

看起来首先需要检查Symbol.iterator的属性查找:

NAN_PROPERTY_GETTER(My_Obj::Getter) {
  auto self = Nan::ObjectWrap::Unwrap<My_Obj>(info.This());
  if (property->IsSymbol()) {
    if (Nan::Equals(property, v8::Symbol::GetIterator(info.GetIsolate())).FromJust()) {
      ...

编写一个不带参数的函数,该函数返回一个对象,其中 next 属性设置为另一个函数:

      ...
      auto iter_template = Nan::New<v8::FunctionTemplate>();
      Nan::SetCallHandler(iter_template, [](const Nan::FunctionCallbackInfo<v8::Value> &info) {
          auto next_template = Nan::New<v8::FunctionTemplate>();
          Nan::SetCallHandler(next_template, My_Obj::next, info.Data());
          auto obj = Nan::New<v8::Object>();
          Nan::Set(obj, Nan::New<v8::String>("next").ToLocalChecked(),
                   next_template->GetFunction());
          info.GetReturnValue().Set(obj);
        }, info.This());
      info.GetReturnValue().Set(iter_template->GetFunction());
      ...

next函数也不需要参数。每次调用时,它会按顺序返回迭代值。我在这里使用了C++迭代器:

NAN_METHOD(My_Obj::next) {
  auto self = Nan::ObjectWrap::Unwrap<My_Obj>(info.Data().As<v8::Object>());
  bool done = self->iter == self->contents.end();
  auto obj = Nan::New<v8::Object>();
  Nan::Set(obj, Nan::New<v8::String>("done").ToLocalChecked(),
           Nan::New<v8::Boolean>(done));
  if (!done) {
    Nan::Set(obj, Nan::New<v8::String>("value").ToLocalChecked(),
             Nan::New<v8::String>(self->iter->first.c_str()).ToLocalChecked());
  }
  self->iter++;
  info.GetReturnValue().Set(obj);
}

我正在将状态保存在包装对象本身中。这使得此生成器不可重入。对于读/写对象来说,这可能是可以接受的,但对于只读对象,可能需要采用其他状态保持方法。 一个示例对象的完整代码可用。

似乎最重要的第一步是检查Symbol.iterator的属性查找,有没有方法在Node.js 0.12中实现这个功能?V8 3.28.71.19中的Symbol类似乎没有GetIterator函数。 - Jan Hecking

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接