Как сопоставить функцию JavaScript, возвращающую асинхронный итератор в Dart, используя package: js?

#javascript #flutter #dart #webapi #dart-js-interop

#javascript #flutter #dart #webapi #dart-js-interop

Вопрос:

Я хотел бы использовать window.showDirectoryPicker() метод из Dart / Flutter. Использование его из JavaScript, позволяющее пользователю выбирать каталог, а затем перечислять его содержимое, работает следующим образом:

 const dirHandle = await window.showDirectoryPicker();
for await (const entry of dirHandle.values()) {
  console.log(entry.name);
}
 

В документах FileSystemDirectoryHandle.values() говорится, что он возвращает «новый итератор массива, содержащий значения для каждого индекса в FileSystemDirectoryHandle объекте». В нем конкретно не указано, хотя, похоже, это асинхронный итератор, как того требует перечисление await for .

Я пытаюсь создать привязки для вызова этого из Dart. Я ожидаю, что моя привязка должна возвращать a Stream<FileSystemHandle> , хотя я не могу найти никаких примеров или документов об этом. Я перепробовал много комбинаций вещей, хотя вот что у меня есть сейчас:

 @JS()
library js_lib;

import 'dart:html';

import 'package:js/js.dart';
import 'package:js/js_util.dart';

Future<FileSystemDirectoryHandle> showDirectoryPicker() =>
    promiseToFuture(callMethod(window, 'showDirectoryPicker', []));

@JS()
abstract class FileSystemDirectoryHandle extends FileSystemHandle {
  external Stream<FileSystemHandle> values();
}

@JS()
abstract class FileSystemHandle {
  String get name;
}

@JS()
abstract class FileSystemFileHandle extends FileSystemHandle {}
 

Я пытаюсь назвать это так:

 final dirHandle = await showDirectoryPicker();
await for (final item in dirHandle.values()) {
  print(item.name);
}
 

Однако это не удается, как с ошибкой:

Ошибка: ожидалось значение типа ‘Stream’, но получено значение типа ‘NativeJavaScriptObject’

Я подозреваю, что мне может понадобиться что-то для преобразования итератора JS в поток Dart (аналогично promiseToFuture вызову, который у меня есть), хотя я не могу найти способ сделать это (я также не могу добавить методы FileSystemDirectoryHandle , которые не external являются .

Комментарии:

1. Разработчик Flutter задает вопрос?

2. Мои вклады в основном сосредоточены на инструментах — я не знаю намного больше, чем знаю 🙂

3. Честно говоря, это было очень мотивирующее заявление для таких людей, как я. Я не понял вопроса (даже не могу подумать о том, чтобы соответствовать вашему уровню), но я уверен, что этот вопрос заслуживает того, чтобы его задать. Но опять же, вы, вероятно, были тем, кто мог ответить на это, и вы просто сделали. 1 и большое вам спасибо 🙂

Ответ №1:

Редактировать: кажется, это работает, build_runner serve но нет build_runner serve --release . Я отправил запрос, чтобы определить, является ли это ошибкой или это неправильный способ сделать это.


Поняв, что асинхронные итераторы в JS — это просто итераторы, которые next() возвращают обещание, я смог написать небольшую функцию, которая просто вызывала метод вручную и выдавала в async* функции:

 extension FileSystemDirectoryHandleExtensions on FileSystemDirectoryHandle {
  Stream<FileSystemHandle> values() =>
      _asyncIterator<FileSystemHandle>(callMethod(this, 'values', []));
}

Stream<T> _asyncIterator<T>(jsIterator) async* {
  while (true) {
    final next = await promiseToFuture(callMethod(jsIterator, 'next', []));
    if (getProperty(next, 'done')) {
      break;
    }
    yield getProperty(next, 'value');
  }
}
 

Это вызывается с использованием исходного кода Dart выше и выводит имена файлов по желанию.