Как мне сделать этот шаблон jquery в дротике?

Я пытаюсь преобразовать следующий код javascript/jquery в dart, но у меня возникают проблемы с пониманием того, как работают фьючерсы.

function fnA() {
    fnB().then(function() {
        // do something
    }
}

function fnB() {
   var ret = $.Deferred();

   _db.open(database_name).then(function() {
       var defers = [];

       _db.keys().forEach(function(key_name) {
          var key_dfd = $.Deferred();
          defers.push(key_dfd);
          _db.getByKey(key_name).then(function(data) {
              key_dfd.resolve(data);
          });
       });
       $.when(defers).then(ret.resolve);
   })
   .fail(function() {
       ret.reject();
   });

   return ret.promise();
}

Я думал, что смогу сделать это аналогично следующему, но, похоже, это не работает:

(Я использую lawndart для базы данных)

void fnA() {
    fnB().then((_) {
        // Here, all keys should have been loaded
    });
}

Future fnB() {
    return _db.open().then((_) {
        return _db.keys().forEach((String key_name) {
             return _db.getByKey(key_name).then((String data) {
                  // do something with data
                  return data;
             });
        });
    });
}

person Naddiseo    schedule 08.05.2014    source источник
comment
Вы не отлавливаете ошибки, возникающие в любом из defers!!! Не используйте свои собственные new Deferred, а просто верните промис, который у вас уже есть...   -  person Bergi    schedule 09.05.2014


Ответы (2)


Я сделал некоторые улучшения, но не тестировал код:

void fnA() {
    fnB().then((_) {
        // Here, all keys should have been loaded
    });
}

Future fnB() {
  return _db.open().then((_) {
    List<Future> futures = [];
    return _db.keys().forEach((String key_name) { 
      futures.add(_db.getByKey(key_name).then((String data) {
        // do something with data
        return data;
      }));
    }).then(() => Future.wait(futures));
  });
}
person Günter Zöchbauer    schedule 09.05.2014
comment
К сожалению, это не сработает, потому что при выполнении Future.wait список futures пуст, так как forEach еще не запущен. - person Naddiseo; 10.05.2014
comment
Это тоже не сработает. () => возвращает функцию, а не Future, чего хочет список. - person Naddiseo; 10.05.2014
comment
() =› возвращает функцию, но .then()... возвращает Future - person Günter Zöchbauer; 31.05.2014

Придерживаясь на мгновение JavaScript/jQuery, fnB можно (при условии совместимости реализаций Promise) написать более эффективно следующим образом:

function fnB() {
    return _db.open(database_name).then(function() {
        return $.when.apply(null, _db.keys().map(function(key_name) {
            return _db.getByKey(key_name);
        }));
    });
}

Насколько я могу судить из документации Dart, это должно переводиться в Dart примерно так:

function fnB() {
    return _db.open().then(function() {
        return Future.wait(_db.keys().map(function(key_name) {
            return _db.getByKey(key_name);
        }));
    });
}

Предположение о совместимости Promise при переводе исчезает, но приведенный выше код предполагает, что _db.keys() возвращает массив. Если это предположение неверно, код будет немного другим.

fnA будет примерно таким:

function fnA() {
    fnB()
        .then((List values) => doSomething(values))
        .catchError((e) => handleError(e));
}

В этом суть. Возможно, вам придется поработать над деталями.

person Roamer-1888    schedule 09.05.2014
comment
_db.keys() возвращает Stream, поэтому сложно получить из него List<Future>. - person Naddiseo; 10.05.2014
comment
@Naddiseo, ага, так это поток - (а потоки - неуклюжие дьяволы). Как я это вижу, цель fnB состоит в том, чтобы выполнить _db.keys(), отобразить возвращенный поток в массив (фьючерсов) и передать этот массив Future.wait(). Судя по тому, что я прочитал в документации Dart, это по существу верно, но, как я уже сказал, вам, возможно, придется поработать над деталями. - person Roamer-1888; 10.05.2014