Parfois, l'utilisateur démarre une opération technique étendue qui prend un certain temps à exécuter. Dans ces cas, il est généralement agréable d'afficher une sorte de barre de progression, ainsi que des informations sur la tâche en cours d'exécution.
Afin d'éviter de coupler étroitement l'interface utilisateur et les couches logiques, il est généralement préférable que la communication se fasse via une sorte de proxy. Autrement dit, le back-end ne doit pas manipuler ses propres éléments d'interface utilisateur, ni même interagir directement avec la couche intermédiaire.
De toute évidence, il doit y avoir un rappel quelque part pour que cela fonctionne. Je l'ai généralement implémenté de deux manières:
Passez un objet modifiable au back-end et demandez-lui de le modifier au fur et à mesure. L'objet avertit le serveur frontal lorsqu'un changement se produit.
Passez une fonction de rappel du formulaire
void f(ProgressObject)
ouProgressObject -> unit
que le back-end invoque. Dans ce cas, le back-end construit leProgressObject
et il est complètement passif. Il doit construire un nouvel objet à chaque fois qu'il veut rendre compte des progrès, je suppose.
Quels sont les inconvénients et les avantages de ces méthodes? Existe-t-il une meilleure méthode convenue à utiliser? Y a-t-il des circonstances différentes pour leur utilisation?
Y a-t-il des techniques complètement différentes pour signaler les progrès que j'ai ignorées?
la source
BackgroundWorker
ce RH mentionne. Enveloppé dans une classe personnalisée avec un "formulaire de progression", etc. et un mécanisme simple pour communiquer une exception - commeBackgroundWorker
par conception s'exécute dans un thread séparé. Dans la mesure où nous utilisons ses fonctionnalités d'une manière suggérée par .Net, cela pourrait être considéré comme idiomatique. Et dans n'importe quel contexte de langage / cadre donné, "idiomatique" peut être le meilleur.Réponses:
Il est difficile d'équilibrer l'efficacité si le back-end le notifie à cet égard. Sans précaution, vous pourriez constater que l'augmentation de votre progression finit par doubler ou tripler le temps nécessaire pour terminer l'opération si vous visez une mise à jour de progression très fluide.
Je ne comprends pas tellement la différence ici.
Sondage depuis le front-end dans un thread séparé avec des incréments atomiques dans le backend. L'interrogation est logique ici, car il s'agit d'une opération qui se termine dans une période finie et la probabilité que le frontend détecte des changements d'état est élevée, surtout si vous visez une barre de progression lisse et soyeuse. Vous pouvez envisager des variables de condition si vous n'aimez pas l'idée d'interroger à partir du thread frontal, mais dans ce cas, vous voudrez peut-être éviter de notifier chaque incrément de barre de progression granulaire.
la source
C'est la différence entre un mécanisme de notification push et pull .
L'objet mutable (l' extraction ) devra être interrogé de manière répétée par l'interface utilisateur et synchronisé si vous vous attendez à ce que la tâche principale soit exécutée dans un thread d'arrière-plan / de travail.
Le rappel (le push ) ne créera du travail pour l'interface utilisateur que lorsque quelque chose change réellement. De nombreux frameworks d'interface utilisateur ont également un appel invokeOnUIThread à partir d'un thread de travail pour faire exécuter un morceau de code sur le thread d'interface utilisateur afin que vous puissiez réellement apporter les modifications sans entrer dans les dangers liés au thread. (jeu de mots volontaire)
En général, les notifications push sont préférables car elles ne fonctionnent que lorsque le travail doit être fait.
la source
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.
- Pas si l'objet modifiable est la boîte de dialogue elle-même ou une interface de travail avec elle. Bien sûr, cela équivaut à un rappel de toute façon.J'utilise des websockets avec AngularJS. Lorsque le frontal reçoit un message, il l'affiche dans une zone de message désignée qui s'estompe pour s'éteindre après quelques secondes. À l'arrière, je poste simplement des messages d'état dans une file d'attente de messages. J'envoie uniquement du texte, mais il n'y a aucune raison pour laquelle je n'ai pas pu envoyer d'objet d'état avec des valeurs telles que le pourcentage d'achèvement ou la vitesse de transfert.
la source
Vous mentionnez vos «deux façons» comme s'il s'agissait de concepts distincts, mais je veux y revenir un peu.
Vous avez déjà dit que vous vouliez éviter de coupler étroitement l'interface utilisateur et la logique, je peux donc supposer en toute sécurité que cet "objet mutable" que vous passez est en fait une implémentation d'une interface particulière définie dans le module logique. En tant que tel, c'est simplement une autre façon de passer un rappel dans le processus qui est périodiquement appelé avec des informations sur les progrès.
Quant aux avantages et inconvénients ...
Un inconvénient de la méthode (1) est que la classe qui implémente l'interface ne peut le faire qu'une seule fois. (Si vous souhaitez effectuer différents travaux avec différentes invocations, vous aurez besoin d'une instruction switch ou du modèle de visiteur.) Avec la méthode (2), le même objet peut utiliser un rappel différent pour chaque invocation du code backend sans avoir besoin d'un commutateur.
La force de la méthode (1) est qu'il est beaucoup plus facile d'avoir plusieurs méthodes sur l'interface que de traiter les rappels multiples de la méthode (2) ou un seul rappel avec une instruction switch pour plusieurs contextes.
la source
Les techniques que vous pouvez utiliser peuvent être très différentes.
J'essaie de comprendre avec un scénario différent
Une simple demande de connexion à db (signifie répondre à partir de db avec un elemt) n'a pas besoin d'un rapport de progression mais il peut toujours déclencher le thread d'interface utilisateur dans une tâche séparée ex. async ou backgroundworker, ici vous avez juste besoin d'un rappel pour le résultat.
Mais que se passe-t-il si vous demandez à voir tout votre inventaire avec un article de 1 mln? Cette requête devrait prendre plusieurs minutes, donc dans ce cas, vous devez implémenter la progression de votre port dans votre logique métier sous la forme élément / éléments, puis vous pouvez mettre à jour votre interface utilisateur et vous pouvez donner l'option annuler le rappel.
Même cas pour le téléchargement de fichiers. Vous pouvez toujours implémenter ici votre rappel de progression sous la forme d'octets d'octets, et maintenir tout le contrôle de la communication sur http est très souvent un modèle.
Dans mon approche personnelle, j'implémente ma logique de progression commerciale uniquement à mes clients, en évitant de partager d'autres objets avec le point final.
la source