A veces, el usuario inicia una operación técnica extendida que demora un tiempo en ejecutarse. En estos casos, generalmente es bueno mostrar algún tipo de barra de progreso, junto con información sobre qué tarea se está ejecutando en este momento.
Para evitar el acoplamiento cercano de la interfaz de usuario y las capas lógicas, generalmente es mejor que la comunicación se produzca a través de algún tipo de proxy. Es decir, el back-end no debe manipular sus propios elementos de la interfaz de usuario, o incluso interactuar directamente con la capa intermedia.
Obviamente, debe haber alguna devolución de llamada en algún lugar para que esto funcione. Generalmente lo he implementado de una de dos maneras:
Pase un objeto mutable al back-end y haga que el back-end le haga cambios en el progreso. El objeto notifica al front-end cuando ocurre un cambio.
Pase una función de devolución de llamada del formulario
void f(ProgressObject)
oProgressObject -> unit
que invoque el back-end. En este caso, el back-end construyeProgressObject
y es completamente pasivo. Supongo que debe construir un nuevo objeto cada vez que quiera informar sobre el progreso.
¿Cuáles son los inconvenientes y las ventajas de estos métodos? ¿Existe un mejor método acordado para usar? ¿Existen diferentes circunstancias para su uso?
¿Hay técnicas completamente diferentes de informar el progreso que he pasado por alto?
fuente
BackgroundWorker
menciones de RH. Envuelto en una clase personalizada junto con un "formulario de progreso", etc. y un mecanismo simple para comunicar una excepción, comoBackgroundWorker
por diseño se ejecuta en un hilo separado. En la medida en que usemos sus características de una manera sugerida por .Net, entonces podría decirse que es idiomático. Y en cualquier contexto de lenguaje / marco dado, "idiomático" puede ser lo mejor.Respuestas:
Es difícil equilibrar la eficiencia si el backend lo notifica a este respecto. Sin cuidado, es posible que aumentar su progreso termine duplicando o triplicando el tiempo que lleva completar la operación si está buscando una actualización de progreso muy fluida.
No entiendo mucho la diferencia aquí.
Encuesta desde el front-end en un hilo separado con incrementos atómicos en el backend. El sondeo tiene sentido aquí, ya que es para una operación que finaliza en un período finito y la probabilidad de que el frontend recoja los cambios de estado es alta, especialmente si está buscando una barra de progreso suave y sedosa. Puede considerar las variables de condición si no le gusta la idea de sondeo desde el hilo de la interfaz, pero en ese caso es posible que desee evitar notificar cada incremento granular de la barra de progreso.
fuente
Esta es la diferencia entre un mecanismo de notificación push y pull .
El objeto mutable (la extracción ) deberá ser sondeado repetidamente por la interfaz de usuario y sincronizado si espera que la tarea de fondo se ejecute en un subproceso de fondo / trabajador.
La devolución de llamada (la inserción ) solo creará trabajo para la interfaz de usuario cuando algo realmente cambie. Muchos marcos de UI también tienen un invokeOnUIThread invocable desde un subproceso de trabajo para hacer que se ejecute un fragmento de código en el subproceso de la IU para que pueda realizar los cambios sin entrar en peligro relacionado con el subproceso. (juego de palabras previsto)
En general, las notificaciones push son preferibles porque solo hacen el trabajo cuando hay que hacerlo.
fuente
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.
- No si el objeto mutable es el diálogo en sí, o una interfaz de trabajo para él. Por supuesto, eso equivale a una devolución de llamada de todos modos.Estoy usando websockets con AngularJS. Cuando el front end recibe un mensaje, lo muestra en un área de mensaje designada que se desvanece en blanco después de unos segundos. En el back-end solo publico mensajes de estado en una cola de mensajes. Solo envío mensajes de texto, pero no hay razón para no poder enviar un objeto de estado con valores como porcentaje completado o velocidad de transferencia.
fuente
Mencionas tus "dos formas" como si fueran conceptos separados pero quiero retrasar un poco eso.
Ya ha dicho que desea evitar el acoplamiento estrecho de la interfaz de usuario y la lógica, por lo que puedo suponer con seguridad que este "objeto mutable" que está pasando es en realidad una implementación de una interfaz particular que se define en el módulo lógico. Como tal, esta es simplemente otra forma de pasar una devolución de llamada al proceso que periódicamente llama con información sobre el progreso.
En cuanto a los beneficios y desventajas ...
Un inconveniente del método (1) es que la clase que implementa la interfaz solo puede hacerlo una vez. (Si desea realizar diferentes trabajos con diferentes invocaciones, necesitará una declaración de cambio o el patrón de visitante). Con el método (2), el mismo objeto puede usar una devolución de llamada diferente para cada invocación del código de fondo sin la necesidad de un cambiar.
Una fortaleza del método (1) es que es mucho más fácil tener múltiples métodos en la interfaz que lidiar con las múltiples devoluciones de llamada o la devolución de llamada única del método (2) con una declaración de conmutación para múltiples contextos.
fuente
Las técnicas que puede usar pueden ser muy diferentes.
Trato de averiguar con diferentes escenarios
Una simple solicitud de inicio de sesión a db (respuesta media de db con un elemento) no necesita un informe de progreso, pero siempre puede disparar el hilo de la interfaz de usuario en tareas separadas, por ejemplo. Async o backgroundworker, aquí solo necesita una devolución de llamada para el resultado.
Pero, ¿qué sucede si consulta para ver todo su inventario con un artículo de 1 mln? Esta consulta debería tardar varios minutos en completarse, por lo que en este caso debe implementar su progreso de perport en su lógica de negocios en elementos / elementos de formulario, luego puede actualizar su UI y se le puede dar la opción de cancelar la devolución de llamada.
El mismo caso para la descarga de archivos. Siempre puede implementar aquí su devolución de llamada de progreso en bytes de forma, y mantener todo el control de comunicación sobre http es un patrón muy común.
En mi enfoque personal, implemento la lógica de progreso de mi negocio solo para mis clientes, evitando compartir otro objeto con el punto final.
fuente