1
votes

Problème pour obtenir la mise à jour DOM dans Vue.js en attendant la fin de la promesse

Je ne connais pas très bien les promesses de JS bien que j'en sache généralement assez pour être dangereux. Je travaille sur la méthode Vue qui gère la recherche d'un objet de données volumineux présent dans this.data () - Normalement, lorsque je fais des requêtes asynchrones via axios, ce même formatage fonctionne bien mais dans ce cas, je dois créer manuellement une promesse pour obtenir le comportement souhaité. Voici un exemple de code:

        async searchPresets() {

            if (this.presetSearchLoading) {
                return
            }

            this.presetSearchLoading = true; // shows spinner
            this.presetSearchResults = []; // removes old results
            this.selectedPresetImports = []; // removes old user sections from results

            // Need the DOM to update here while waiting for promise to complete
            // otherwise there is no "loading spinner" feedback to the user.
            const results = await new Promise(resolve => {

                let resultSet = [];
                for (var x = 0; x < 10000; x++) {
                    console.log(x);
                }

                let searchResults = [];
                // do search stuff
                resolve(searchResults);

            });

            // stuff after promise

        }

Le fait est que le truc après la promesse fonctionne correctement. Il attend la résolution avant de s'exécuter et reçoit les données de résultat de recherche appropriées comme il se doit.

Le problème est que le DOM ne se met pas à jour lors de l'envoi de la promesse, donc l'interface utilisateur reste juste là.

Quelqu'un sait-il ce que je fais de mal?


4 commentaires

Pourquoi pensez-vous que DOM n'est pas mis à jour? Le spinner n'apparaît-il pas pendant que l'async promis attend d'être résolu? Êtes-vous sûr que le spinner affichant la logique fonctionne correctement? Peut-être que le spinner est affiché pendant une seconde rapide car la promesse asynchrone est résolue rapidement. Pouvez-vous essayer d'ajouter un délai pour voir si cela aide?


Oui, je suis sûr. Je suis revenu hors de la fonction en définissant la variable qui montre le spinner et cela fonctionne. J'ai également ajouté cette boucle pog pour prolonger la durée de la promesse indiquée dans mon exemple de code. Je peux voir l'impression des journaux mais pas de spinner.


Quel est le "truc après promesse"? C'est là que vous mettez à jour les données du composant, non?


C'est là que je désactiverais le spinner, etc. Le problème est avant cela, donc ce n'est pas pertinent. Dans mon test, ce code est correctement exécuté une fois la promesse terminée. Comme je l'ai dit, le problème est que le dôme ne se met pas à jour comme il le fait avec les appels axios.


3 Réponses :


1
votes

Essayez $ nextTick () :

Vue 2.1.0+:

const results = await new Promise(resolve => {                      
  this.$nextTick(() => {
    let resultSet = []
    for (var x = 0; x < 10000; x++) {
      console.log(x)
    }

    let searchResults = []
    // do search stuff
    resolve(searchResults)
  })
})

N'importe quelle vue:

const results = await this.$nextTick().then(() => {                      
  let resultSet = []
  for (var x = 0; x < 10000; x++) {
    console.log(x)
  }

  let searchResults = []
  // do search stuff
  return searchResults
});


2 commentaires

J'essaierai cette première chose le matin


N'a pas donné le résultat souhaité, mais merci de lui donner une chance :)



0
votes

Vue recherchera les modifications de données et les collectera dans un tableau pour dire si le DOM doit être rendu par la suite. Cela signifie que tout dans Vue est piloté par les événements (données). Votre fonction définit uniquement un comportement qui n'a aucune liaison de données avec le V-DOM. Donc, le moteur Vue ne fera rien puisque rien dans leur ensemble de données dépendant n'a changé.

Je vois que votre fonction Promise va résoudre la réponse à une variable "searchResults". Si votre DOM utilise cette variable, le moteur Vue collectera la modification une fois la promesse effectuée. Vous pouvez mettre une propriété dans "data ()" et la lier à DOM.

Par exemple:

<span v-for="(res, key) in searchResults" :key="key">
  {{ res.name }}
</span>
...
<script>
  export default {
    ...
    data () {
      return { searchResults: [] }
    },
    ...
  }
</script>


1 commentaires

Je comprends comment la vue fonctionne et votre réponse ne se rapproche pas de ma question mais merci.



0
votes

Il s'avère donc que j'ai en quelque sorte tout dit quand j'ai dit: "Je ne suis pas très au fait des promesses de JS bien que j'en sache généralement assez pour être dangereux.".

J'apprécie les tentatives pour m'aider à traverser cela, mais il s'avère que faire quelque chose comme une promesse ne le rend pas intrinsèquement asyncrone. C'était mon erreur. Le problème n'était pas que Vue ne mettait pas à jour le DOM, le problème était que le code de promesse s'exécutait de manière synchrone et bloquait - ainsi parce que l'exécution ne s'est jamais vraiment arrêtée pour attendre, Vue n'avait aucun perogatif pour mettre à jour le DOM.

Une fois que j'ai enveloppé mon code de promesse dans un setTimout (() => {/ * tout le code ici, alors: * / resolution (searchResults);}, 200); Tout a commencé à fonctionner. Je suppose que le délai d'expiration permet à l'exécution de s'arrêter suffisamment longtemps pour que la vue change le dom en fonction de mes modifications de données précédentes. Le script bloque toujours techniquement l'interface utilisateur pendant son exécution, mais au moins mon chargeur tourne pendant ce processus, ce qui est assez bon pour ce que je fais ici.

Voir: JavaScript Promise est-il asynchrone?


0 commentaires