Я пытался показать прогресс в ангулардарте и думал, что Future для этого подойдет. Но потом я понял, что Future должно быть рекурсивным, чтобы показывать прогресс, поскольку Future возвращается немедленно, а после этого выполняется длительная операция.

Если я создаю Future, который вызывает себя до тех пор, пока не будет выполнено конечное условие, оно будет работать с индикатором выполнения. Но я думаю, что это не может быть очень хорошей практикой, так как эти вызовы будут увеличивать память в стеке с каждой рекурсией. Просто представьте, что цикл проходит через 1 миллиард наборов данных, который может длиться несколько часов, и каждый цикл вызывает новое Будущее в текущем Будущем.

Есть ли лучший способ создать цикл, которому требуется определенное количество времени для работы с каждым элементом (включая вызов веб-сайта, который должен быть асинхронным, и оценку возвращаемого значения)? Во время цикла пользователь должен видеть прогресс, который показывает ему «x / 1000000 done».

Я думаю, что это должно быть сделано с помощью Future, поскольку пользовательский интерфейс должен перезагружаться после запуска цикла, но рекурсивное Future мне кажется плохой идеей.

1
zreptil 24 Сен 2018 в 14:02

2 ответа

Лучший ответ

Тем временем я понял, что Future-метод немедленно возвращается, не выполняя ничего в теле метода. Итак, решение довольно простое:

Просто объявите rpc с помощью Future, сделайте все, что вам нужно, в методе и при его вызове используйте then (...), чтобы делать то, что вам нужно сделать после сбора данных.

int progress = 0;
int progressMax = 100;
bool progressCanceled = false;

Future rpc(var data)
async{
  for(progress=0; progress<progressMax, progress++)
  {
    // do whatever you need to do with data
    if(progressCanceled)
      return;
  }
}

rpc(data).then(
{
  if(progressCanceled)
    return;
  // do whatever is needed after having received that data
});

Rpc выполняется, и вызывающий процесс может продолжаться, пока rpc делает то, что должен делать rpc. Основная программа может обрабатывать нажатия кнопок, чтобы установить для progressCanceled значение true, а метод rpc запросит состояние и прекратит обработку, если оно установлено.

0
zreptil 27 Сен 2018 в 08:14

Вам нужно, чтобы будущее сразу же вернулось к вам в Интернете, потому что это однопоточная платформа. Если асинхронное действие не возвращалось до тех пор, пока оно не было завершено, вы бы повесили браузер, и это не принесло бы пользы пользователю.

Вместо этого у вас есть несколько вариантов:

У Dart есть способность сделать будущее синхронным с ключевым словом await. Итак, вы можете сделать что-то вроде:

void performAction() async {
  showProgress = true;
  await expensiveRpc();
  showProgress = false;
}

Это потребует, чтобы прогресс был промежуточным, поскольку вы фактически не обновляете индикатор выполнения по мере его продвижения. Тем не менее, если вы действительно не получаете события прогресса от вашего RPC, это, вероятно, лучшее решение.

Теперь, если ваш RPC или действие дают вам какую-то обратную связь, вы можете сделать что-то более приятное с потоком.

void performAction() {
  showProgress = true;
  expensiveRpc().listen((progress) {
    if (progress.done) {
      showProgress = false;
    } else {
      percentComplete = progress.value;
    });
}

На самом деле это больше зависит от RPC или сервиса, с которым вы взаимодействуете, от того, как вы можете лучше обновить прогресс, чем от самого прогресса.

2
Ted Sander 26 Сен 2018 в 00:04