Вопрос

I have a list of urls that I have to check sequentially. When one of the content retrieved at the url matches a given criteria I have to stop otherwise the next url has to be tested.

The problem is that retrieving content for a given url is an asynchronous task so I can't use a simple for-each loop.

What is the best way to do that ?

For now my code looks like that :

List<String> urls = [/*...*/];
void f() {
  if (urls.isEmpty) return; // no more url available
  final url = urls.removeAt(0);
  getContent(url).then((content) {
    if (!matchCriteria(content)) f(); // try with next url
    else doSomethingIfMatch();
  });
}
f();
Это было полезно?

Решение

The Quiver package contains several functions to iterate with async.

doWhileAsync, reduceAsync and forEachAsync perform async computations on the elements of on Iterables, waiting for the computation to complete before processing the next element.

doWhileAsync seems to be exactly what is wanted :

List<String> urls = [/*...*/];
doWhileAsync(urls, (url) => getContent(url).then((content) {
  if (!matchCriteria(content)) {
    return new Future.value(true); // try with next url
  } else {
    doSomethingIfMatch();
    return new Future.value(false);
  }
}));

Другие советы

One idea that I have is to seperate the result of the whole operation into another Future which on which be reacted on. This future transmits either the content of the URL that was found and is valid or an error on which can be reacted upon. The completion of the async getContent operation either fulfills the future with a result, an error or tries again. Please not that in this (and your) approach that the urls list must not be modified by any other method while the operation is running. If the list is created new on the start of each sequence (like it the example) then everything is fine.

List<String> urls = [/*...*/];
Completer<String> completer = new Completer<String>();

void f() {
  if (urls.isEmpty) completer.completeError(new Exception("not found"));
  final url = urls.removeAt(0);
  getContent(url).then((content) {
    if (!matchCriteria(content)) f(); // try with next url
    else completer.complete(content);
  }).catchError((error) { completer.completeError(error); });
}

completer.future.then((content) {
  // url was found and content retrieved      
}).catchError((error) {
  // an error occured or no url satisfied the criteria
});
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top