简体   繁体   English

How to map a JavaScript function returning an async iterator in Dart using package:js?

[英]How to map a JavaScript function returning an async iterator in Dart using package:js?

I'd like to use the window.showDirectoryPicker() method from Dart/Flutter.我想使用 Dart/Flutter 中的window.showDirectoryPicker()方法 Using it from JavaScript to allow a user to select a directory and then list the contents of it works like this:从 JavaScript 使用它来允许用户 select 一个目录,然后列出它的内容,如下所示:

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

The docs for FileSystemDirectoryHandle.values() say it returns "a new Array Iterator containing the values for each index in the FileSystemDirectoryHandle object." FileSystemDirectoryHandle.values()的文档说它返回“一个新的数组迭代器,其中包含FileSystemDirectoryHandle object 中每个索引的值。” It doesn't say specifically, though it appears to be an async iterator as enumerating it requires await for .它没有具体说明,尽管它似乎是一个异步迭代器,因为枚举它需要await for

I'm trying to create bindings to call this from Dart.我正在尝试创建绑定以从 Dart 调用它。 I expect that my binding should return a Stream<FileSystemHandle> although I can't find any examples or docs about doing this.我希望我的绑定应该返回Stream<FileSystemHandle>尽管我找不到任何关于这样做的示例或文档。 I've tried many combinations of things, though here's what I have now:我已经尝试了很多组合,但这是我现在所拥有的:

@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 {}

I'm trying to call it like this:我试图这样称呼它:

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

However this fails like with the error:但是,这会像错误一样失败:

Error: Expected a value of type 'Stream', but got one of type 'NativeJavaScriptObject'错误:需要一个“Stream”类型的值,但得到一个“NativeJavaScriptObject”类型的值

I suspect I may need something to convert the JS iterator to a Dart stream (similar to the promiseToFuture call I have), although I can't find a way to do that (I'm also unable to add methods to FileSystemDirectoryHandle that aren't external .我怀疑我可能需要一些东西来将 JS 迭代器转换为 Dart stream (类似于我的promiseToFuture调用),尽管我找不到这样做的方法(我也无法向FileSystemDirectoryHandle添加方法t external

Edit: This seems to work in build_runner serve but not build_runner serve --release .编辑:这似乎适用于build_runner serve但不适build_runner serve --release I've filed an issue to determine if this is a bug or this is the wrong way to do this.我已经提交了一个问题,以确定这是一个错误还是执行此操作的错误方法。


After realising the async iterators in JS are just iterators where next() returns a promise, I was able to write a small function that just invoked the method manually and yielded in an async* function:在意识到 JS 中的异步迭代器只是next()返回 promise 的迭代器之后,我能够编写一个小的 function,它只是手动调用该方法并在async* ZC1C425268E68395D1AB4 中产生:

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');
  }
}

This is called using the original Dart code above, and prints the filenames as desired.这使用上面的原始 Dart 代码调用,并根据需要打印文件名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM