Иногда пользователь запускает расширенную техническую операцию, выполнение которой занимает некоторое время. В этих случаях обычно удобно отображать какой-то индикатор выполнения вместе с информацией о том, какая задача выполняется в данный момент.
Чтобы избежать тесной связи между пользовательским интерфейсом и уровнями логики, обычно лучше, чтобы связь происходила через какой-то тип прокси. То есть серверная часть не должна манипулировать своими собственными элементами пользовательского интерфейса или даже напрямую взаимодействовать с промежуточным уровнем.
Очевидно, что где-то должен быть обратный вызов, чтобы сделать эту работу. Я вообще реализовал это одним из двух способов:
Передайте изменяемый объект в бэкэнд, и пусть бэкэнд внесет в него изменения в процессе работы. Объект уведомляет интерфейс, когда происходит изменение.
Передайте функцию обратного вызова в форме
void f(ProgressObject)
или,ProgressObject -> unit
которую вызывает серверная часть. В этом случае серверная часть создаетProgressObject
и она полностью пассивна. Я предполагаю, что он должен создавать новый объект каждый раз, когда хочет сообщить о прогрессе.
Каковы недостатки и преимущества этих методов? Есть ли согласованный лучший метод для использования? Существуют ли разные обстоятельства для их использования?
Существуют ли совершенно разные методы отчетности о прогрессе, которые я пропустил?
источник
BackgroundWorker
это RH упоминает. Завернут в пользовательский класс вместе с «формой прогресса» и т. Д. И простым механизмом сообщения об исключении - так какBackgroundWorker
по замыслу выполняется в отдельном потоке. Если мы будем использовать его возможности способом, предложенным .Net, то это можно назвать идиоматическим. И в любом конкретном языковом / каркасном контексте «идиоматический» может быть лучшим.Ответы:
Трудно сбалансировать эффективность, если бэкэнд уведомляет об этом. Не заботясь, вы можете обнаружить, что увеличение вашего прогресса приводит к удвоению или утроению времени, необходимого для завершения операции, если вы стремитесь к очень плавному обновлению прогресса.
Я не вижу здесь такой разницы.
Опрос от внешнего интерфейса в отдельном потоке с атомными приращениями в внутреннем интерфейсе. Опрос здесь имеет смысл, поскольку он предназначен для операции, которая заканчивается за конечный период, и вероятность изменения состояния внешнего интерфейса высока, особенно если вы стремитесь к гладкому гладкому индикатору выполнения. Вы могли бы рассмотреть условные переменные, если вам не нравится идея опроса из внешнего потока, но в этом случае вы можете избежать уведомления о каждом отдельном увеличении гранулярного индикатора выполнения.
источник
Это разница между нажимным и тяговым механизмом уведомления.
Изменяемый объект ( извлечение ) должен будет повторно опрашиваться пользовательским интерфейсом и синхронизироваться, если вы ожидаете, что фоновая задача будет выполнена в фоновом / рабочем потоке.
Обратный вызов ( push ) создаст работу для пользовательского интерфейса только тогда, когда что-то действительно изменится. Многие фреймворки пользовательского интерфейса также имеют функцию invokeOnUIThread, вызываемую из рабочего потока, для выполнения части кода, выполняемой в потоке пользовательского интерфейса, чтобы вы могли фактически вносить изменения, не вмешиваясь в риски, связанные с потоками. (каламбур предназначен)
В целом push- уведомления предпочтительнее, потому что они выполняют работу только тогда, когда работа должна быть выполнена.
источник
The mutable object (the pull) will need to be repeatably polled by the UI and synchronized if you expect the back-end task to be executed in a background/worker thread.
- Нет, если изменяемый объект - это само диалоговое окно или рабочий интерфейс к нему. Конечно, это равнозначно обратному вызову.Я использую веб-сокеты с AngularJS. Когда пользовательский интерфейс получает сообщение, он отображает его в назначенной области сообщений, которая через несколько секунд становится пустой. На сервере я просто публикую сообщения о состоянии в очереди сообщений. Я только отправляю текст, но нет причин, по которым я не мог отправить объект статуса со значениями, такими как процент выполнения или скорость передачи.
источник
Вы упоминаете свои «два пути», как если бы они были отдельными понятиями, но я хочу немного отступить от этого.
Вы уже сказали, что хотите избежать тесной связи между пользовательским интерфейсом и логикой, поэтому я могу с уверенностью предположить, что этот «изменяемый объект», который вы передаете, на самом деле является реализацией определенного интерфейса, который определен в логическом модуле. Таким образом, это просто еще один способ передачи обратного вызова в процесс, который периодически вызывает информацию о прогрессе.
Что касается преимуществ и недостатков ...
Недостатком метода (1) является то, что класс, реализующий интерфейс, может сделать это только один раз. (Если вы хотите выполнять разные задания с разными вызовами, вам понадобится оператор switch или шаблон посетителя.) При использовании метода (2) один и тот же объект может использовать разный обратный вызов для каждого вызова кода бэкэнда без необходимости переключатель.
Преимущество метода (1) состоит в том, что гораздо проще иметь несколько методов в интерфейсе, чем иметь дело с множественными обратными вызовами метода (2) или одиночным обратным вызовом с оператором switch для нескольких контекстов.
источник
Методы, которые вы можете использовать, могут быть очень разными.
Я пытаюсь разобраться с другим сценарием
Простой запрос на вход в db (имеется в виду ответ от db одним элементом) не требует выполнения отчета, но он всегда может запустить поток пользовательского интерфейса в отдельной задаче ex. async или backgroundworker, здесь вам просто нужен один обратный вызов для результата.
Но что, если вы запросите, чтобы увидеть все ваши ресурсы с 1 млн. Единиц? Выполнение этого запроса может занять несколько минут, поэтому в этом случае вам необходимо реализовать прогресс вашего порта в вашей бизнес-логике в элементе / элементах формы, затем вы можете обновить свой пользовательский интерфейс и, возможно, задать опцию отмены обратного вызова.
Тот же случай для загрузки файла. Здесь вы всегда можете реализовать свой обратный вызов прогресса в виде байтов байтов, и удерживать весь контроль над связью через http очень часто.
На моем личном подходе я применяю логику продвижения своего бизнеса только для своих клиентов, избегая делиться другим объектом с конечной точкой.
источник