Ember.js: [Glimmer 2] "Backtracking re-render" est maintenant une affirmation

Créé le 29 juil. 2016  ·  63Commentaires  ·  Source: emberjs/ember.js

Le retour en arrière fait référence à un scénario dans lequel, au milieu du processus de rendu, vous avez modifié quelque chose qui a déjà été rendu.

Par exemple:

{{foo}} {{foo-bar parent=this}}
// app/components/foo-bar.js

export default Ember.Component.extend({
  init() {
    this._super(...arguments);
    this.get('parent').set('foo', 'bar');
  }  
});

Comme vous pouvez le voir, au moment où le composant foo-bar est instancié et rendu, nous avons déjà utilisé la valeur foo du contexte parent pour remplir le {{foo}} curly. Cependant, dans son constructeur, il essayait de modifier la même valeur, par conséquent. "retour en arrière".

C'est un exemple assez extrême, mais il illustre le problème. Outre init , didInitAttrs , didReceiveAttrs , willInsertElement et willRender se produisent également de manière synchrone pendant le processus de rendu. De plus, le retour en arrière est souvent un problème résultant du comportement des propriétés liées dans les deux sens.

Ce comportement a toujours été peu fiable, mais a été partiellement pris en charge avec une dépréciation (depuis Ember 1.13) :

You modified ApplicationController.foo twice in a single render. This was unreliable in Ember 1.x and will be removed in Ember 3.0

Depuis la 1.13, Ember a pris en charge cela en effectuant immédiatement un deuxième rendu lorsqu'un retour en arrière a été détecté (puis en répétant jusqu'à ce que le système se stabilise). Cette stratégie elle-même pourrait être une source de problèmes de performance. Dans les cas extrêmes, cela pourrait provoquer une boucle infinie.

Dans Glimmer 2, alors que le rendu supplémentaire est relativement bon marché, la comptabilité supplémentaire pour détecter un retour en arrière set ne l'est pas. L'un des avantages du système Glimmer 2 est qu'il n'a pas besoin de configurer avec empressement des observateurs pour suivre les changements. De plus, certaines optimisations de Glimmer 2 permettent au système de sauter les sous-arbres lorsqu'il sait que rien n'a changé.

Ensemble, ces facteurs signifient que nous ne pouvons pas détecter facilement ces set s (ou si quelque chose a été "déjà rendu" ou non) sans faire une grande quantité de comptabilité supplémentaire et sans intentionnellement vaincre ces optimisations.

Nous avons déjà écrit le code pour prendre en charge cela, mais en raison de la nature déjà peu fiable de la fonctionnalité et des coûts de comptabilité (très importants), nous hésitons à les activer automatiquement pour tout le monde sans savoir si cela est encore nécessaire.

En guise de compromis, nous n'effectuons actuellement la détection qu'en mode développement et avons transformé le message de dépréciation en une assertion en mode développement (erreur matérielle). En mode production, le code de détection est supprimé et le retour en arrière ne fonctionnera pas.

Nous avons conservé la possibilité de prendre en charge cette fonctionnalité (sans l'assertion) dans la base de code derrière un deuxième indicateur de fonctionnalité. Le code est testé en continu sur CI, cependant, il est désactivé par défaut jusqu'à ce que nous ayons suffisamment d'informations d'utilisation pour déterminer les prochaines étapes.

Si vous pensez que vos habitudes d'utilisation sont affectées par cela, veuillez fournir le plus de détails possible sur votre scénario ci-dessous. Il est très possible qu'il existe des alternatives et/ou des solutions ciblées que nous pouvons utiliser et qui ne nécessitent pas de changement complet du moteur. Par conséquent, il serait utile que vous fournissiez des informations générales et contextuelles sur votre utilisation au lieu de simplement nous montrer de petits extraits de code de votre base de code.

Ember 2.10 Inactive

Commentaire le plus utile

Cela n'a pas été mentionné dans l'article de blog 2.10 et m'a pris par surprise puisque l'avertissement de dépréciation indiquait précédemment qu'il serait pris en charge jusqu'à la version 3.0, comme mentionné ci-dessus.

Tous les 63 commentaires

Pour info, nous avons eu certains de ces avertissements dans notre application. Plus précisément, nous avons mis à jour certaines propriétés d'un service dans le init d'un composant, ce qui déclencherait un autre élément sur la page pour un rendu différent.

Il est très simple de corriger cet avertissement en planifiant le changement de propriété lors de la prochaine boucle d'exécution. Il m'a fallu environ une heure pour rechercher et corriger tous les avertissements de notre application (assez grande). Bien qu'il s'agisse techniquement d'un changement décisif, je suis d'accord avec votre évaluation même si cela m'a causé du travail supplémentaire.

@fivetanley améliorer le message d'erreur ici semble bien. Je sais que @krisselden et @stefanpenner ont un flux de travail pour suivre ces problèmes, peut-être qu'ils peuvent vous aider à vous donner des indications à ce sujet.

@joukevandermaas run.next() n'est pas une bonne solution pour cette erreur, même si je comprends que si vous êtes submergé par ces erreurs, pourquoi vous y iriez. Il est préférable d'essayer de comprendre pourquoi le reflux de données invalide des éléments déjà rendus.

Il est probable que si vous définissez des accessoires sur un service qui pourraient être injectés sur n'importe quel composant, cela augmente les chances que cet ensemble invalide quelque chose qui a déjà été rendu. En général, le modèle devrait être que set() n'est utilisé que sur l'état interne pendant les hooks de rendu, non lié à l'entrée ou aux services et ou set() est utilisé sur un événement, l'état de l'entrée doit être réglé au moment où les éléments sont rendus.

@joukevandermaas run.next() n'est pas une bonne solution pour cette erreur,

cela cause des problèmes de performances, car glimmer2 dans ce cas informe "un travail en double est en train de se produire, vous n'en voulez vraiment pas si vous voulez une application performante". Là où auparavant, la braise absorberait cela, mais entraînerait une pénalité de performance lourde.

Nous avons encore du travail de partage de connaissances à faire ici... En fin de compte, nous pensons que c'est une voie à suivre saine pour les applications. Mais nous devons nous assurer que tout le monde a les outils + les connaissances disponibles pour en bénéficier :)

En tant que personne qui suit les activités d'Ember d'assez près (twitter, ici sur github, listes de diffusion, etc.), ce problème s'est faufilé sur moi, donc je soupçonne que cela pourrait surprendre les autres s'il atterrit dans le cadre d'Ember 2.10, en particulier parce que l'avertissement d'obsolescence qui lui est associé indique spécifiquement que le comportement sera pris en charge jusqu'à la version 3.0. Je ne crois pas l'avoir vu socialisé nulle part que ce comportement ne fonctionnera pas dans Glimmer 2 (bien que je l'ai peut-être tout simplement manqué).

soupçonnez que cela pourrait surprendre les autres s'il atterrit dans le cadre d'Ember 2.10, en particulier parce que l'avertissement de dépréciation qui lui est associé indique spécifiquement que le comportement sera pris en charge jusqu'à la version 3.0. Je ne crois pas l'avoir vu socialisé nulle part que ce comportement ne fonctionnera pas dans Glimmer 2 (bien que je l'ai peut-être tout simplement manqué).

oui, nous devons améliorer certains messages/détails ici.

Je vois que cela a été intégré à la version 2.10. Cela sera-t-il mentionné dans le billet de blog de la version 2.10 ?

Cela n'a pas été mentionné dans l'article de blog 2.10 et m'a pris par surprise puisque l'avertissement de dépréciation indiquait précédemment qu'il serait pris en charge jusqu'à la version 3.0, comme mentionné ci-dessus.

J'ai un modèle d'utilisation qui est affecté par cela. Je suis sûr que le problème doit être mon modèle d'utilisation, et non ce changement particulier, mais j'aimerais avoir votre avis sur ce que serait un bon modèle d'utilisation alternatif !

Fondamentalement, j'ai une page qui affiche un ensemble de données filtrable, et pour y parvenir, j'utilise une valeur calculée Ember pour filtrer les données en fonction de la valeur de plusieurs paramètres de requête sur la page. Cependant, pour éviter que des entrées non valides (par exemple, des lettres ou des chiffres) ne soient ajoutées aux paramètres de requête à partir de l'entrée utilisateur, j'ai le modèle suivant :

 filteredModel: Ember.computed('model', /*list of individual query params*/, function(){
    let model = this.get('model').filterBy('pdf.pdf_path.url'); //removes all records that don't have a pdf uploaded
    this.get('queryParams').forEach((filter)=> { // for each possible filter
      if ((this.get(filter).length > 0)) { //if the filter has content...
        //guardian pattern to prevent invalid inputs
        let valid = new RegExp('^[A-Za-z0-9 _]*[A-Za-z0-9][A-Za-z0-9 _]*$');
        while (this.get(filter).length > 0 && !valid.test(this.get(filter))){
          this.set(filter, this.get(filter).slice(0,-1));
        }
        //block of code where the model gets filtered
        //...
        //...
    });
    return model;
  }),

Donc, fondamentalement, lorsque j'ai calculé à quoi devrait ressembler le modèle filtré, si l'une des valeurs de filtre contient des caractères invalides, je supprime le dernier caractère jusqu'à ce qu'il devienne valide. Quelqu'un a-t-il une suggestion sur un moyen plus propre de vérifier la validité de ces entrées ?

Cela nous a également pris par surprise - en particulier parce que nous n'avons vu aucun message d'avertissement lorsque l'application s'exécutait avec la version 2.9. Lorsque nous passerons à la version 2.10, l'application ne se chargera pas et fera référence à cette erreur. Est-ce que quelqu'un d'autre a vu ce comportement ?

@revanar Je pourrais être totalement absent, mais il semble que votre CP soit en fait deux choses différentes : un CP pour renvoyer le modèle filtré et un pour mettre à jour les filtres. Je déplacerais la mise à jour de la partie des filtres dans un observable. Ou, s'il s'agit d'un composant et que vous passez les paramètres de requête dans le composant, je déplacerais la logique dans le crochet didReceiveAttrs . D'après mon expérience avec l'erreur "backtracking render", je pense que le déplacement de l'opération set hors du CP devrait faire disparaître l'erreur.

On a aussi du mal avec ça. J'ai résolu de nombreux problèmes, mais un exemple de cette erreur d'obsolescence est déroutant.

Assertion Failed: You modified transitioningIn twice on <app<strong i="6">@component</strong>:link-to::ember1159> in a single render.

Il semble qu'un échec se produise car une propriété interne de braise est mise à jour plusieurs fois. Malheureusement, il se reproduit lors de nos tests sélénium, il est donc difficile à déboguer (le pilote sélénium empêche les outils de développement de fonctionner pendant le test). J'ai tracé au moins une instance du problème jusqu'à un appel controller.transitionToRoute effectué à la fin de notre processus de connexion, mais cela semble se produire dans plusieurs scénarios différents.

Je ne sais pas comment procéder pour résoudre ce problème.

@chancancode a mentionné un indicateur de fonctionnalité pour désactiver cette erreur d' https://github.com/emberjs/ember.js/blob/master/FEATURES.md. Est-ce que quelqu'un sait ce qu'est le drapeau ?

Pour notre migration ember 2.10 également, c'est le principal problème. Nous avons également résolu un grand nombre de ces problèmes. Il semble qu'il n'y ait pas de stratégie unique/claire pour corriger ces erreurs. Nous avons essayé les approches suivantes, selon le cas d'utilisation

  1. Envelopper le code dans Ember.run.next
  2. Déplacer n'importe quel code setter de computed properties dans des hooks de cycle de vie, ou dans event handlers , dans la mesure du possible.
  3. Essayer différentes combinaisons de crochets de cycle de vie pour les composants

Nous avons également eu beaucoup de difficultés avec cela. Au cours des dernières années, nous avons accumulé une bonne quantité de listes déroulantes qui sélectionnent automatiquement le premier élément d'un certain type dans le cache du magasin de données de braises. Cela provoque un nouveau rendu puisque certaines parties de la page sont pilotées par la sélection déroulante. Je ne sais pas trop quoi faire car je ne veux pas répéter le même code pour remplir et sélectionner le premier élément de la liste sur chaque page sur laquelle les listes déroulantes sont utilisées.

@scottmessinger Merci pour le retour. L'utilisation d'un composant a fini par fonctionner assez bien. J'ai réussi à me débarrasser de l'erreur de retour en arrière et je pense que mon code est un peu plus propre pour cela.

Kris Selden a une astuce utile pour les déboguer :

screen shot 2016-12-12 at 13 10 44

J'ai décrit les étapes plus en détail ici : https://github.com/GavinJoyce/backtracking/pull/1#issuecomment -266427152

Je travaille sur l' amélioration du message d'assertion de retour en arrière . J'ai coupé une version 2.10.2-with-improved-backtracking-assertion qui inclut ces meilleurs messages :

Avant:

Vous avez modifié message.message_goal.description deux fois sur <(subclass of Ember.Model):ember3486> en un seul rendu. Ce n'était pas fiable et lent dans Ember 1.x et n'est plus pris en charge. Voir https://github.com/emberjs/ember.js/issues/13948 pour plus de détails.

Après:

Vous avez modifié message.message_goal.description deux fois sur <(subclass of Ember.Model):ember3486> en un seul rendu. Il a été rendu en component:message-edit-expanding-container-component et modifié en component:rules/predicate-date-value-component . Ce n'était pas fiable et lent dans Ember 1.x et n'est plus pris en charge. Voir #13948 pour plus de détails.

J'ai encore quelques choses à faire avant qu'il ne soit prêt, mais ce serait vraiment utile si quelques personnes essayaient cela dans leur application. /cc @fivetanley , @bryanhickerson , @revanar , @phammers , @scottmessinger , @tharrington1 , @manimis902 , @jakesjews , @elwayman02. Veuillez me faire savoir si vous voyez des messages d'assertion non idéaux dans votre application.

Pour l'essayer, mettez à jour votre bower.json pour inclure la dépendance de braise comme suit :

{
  "name": "backtracking",
  "dependencies": {
    "ember": "intercom/ember#2.10.2-with-improved-backtracking-assertion",
    "ember-cli-shims": "0.1.3"
  },
  "resolutions": {
    "ember": "2.10.2-with-improved-backtracking-assertion"
  }
}

Vous pouvez voir un exemple d'application exécutant cette version ici : https://github.com/GavinJoyce/backtracking/pull/10

Je viens de couper une version 1.11.0-canary

Est-ce une faute de frappe ?

@rwjblue merci, c'était une faute de frappe. Mis à jour

@GavinJoyce merci d'avoir pris cela! J'ai essayé cela dans notre application et c'est certainement _plus_ utile que le message précédent. Malheureusement pour nous, cela ne facilite toujours pas la résolution de ce problème, car la propriété qu'il note comme étant modifiée n'est évidemment pas modifiée dans l'un ou l'autre des emplacements indiqués par le message d'erreur. Je ne sais pas exactement pourquoi, mais nous espérons creuser davantage l'année prochaine.

@Dhaulagiri si vous êtes intéressé, je serais heureux d'organiser un

FWIW J'ai trouvé un autre problème lié à cela : https://github.com/alexspeller/ember-cli-active-link-wrapper/issues/25

J'ai également essayé la branche de

@bjornharrtell avez-vous une branche de papier de braise que je peux essayer ?

^ Nous avons pris un peu de temps pour nous plonger dans les problèmes de papier de braise (https://github.com/miguelcobain/ember-paper/pull/590). Il paraît que:

  • les nouveaux messages d'erreur étaient plus utiles que l'actuel
  • ils n'étaient pas parfaits car ils ne géraient pas bien le contenu généré. (le composant qui contenait le {{yield}} été signalé comme la source qui était utile, mais pas aussi utile qu'il pourrait peut-être l'être)

Il peut s'agir ou non d'un bogue avec l'addon, mais j'ai rencontré cette erreur dans https://github.com/DockYard/ember-one-way-controls/issues/136

J'ai trouvé un problème.
J'utilise un mixin qui a un point d'entrée pour mettre à jour la même propriété pour le contrôleur auquel il a été mixé. Ce sont des propriétés définitivement différentes car elles appartiennent simplement à différents contrôleurs et l'assertion échoue et bloque js.
J'ai testé mixin en le déballant dans quelques contrôleurs et en faisant une transition entre les routes à reproduire - il n'a pas été reproduit.

Pour l'instant, j'essaie de me débarrasser des mixins, donc je vais simplement le tuer et créer un travail de contournement.

Je crois que j'ai un cas d'utilisation valide où nous voyons ce problème de ré-rendu. Dans notre application, nous avons un bouton qui contient un état (ok, validation, avertissement, erreur). C'est un composant qui affiche l'état actuel, valide lorsque certaines choses se produisent et, en fonction du résultat de la validation ou de l'activation, affiche différentes choses (spinners, texte de bouton différent, classe de bouton différente).

Nous vérifions la validation sur init() et en fonction de la réponse de validation, définissons l'état du bouton approprié. La classe Button est une propriété calculée qui définit les classes appropriées en fonction de l'état du bouton. Comme cela se produit lors de l'initialisation, il semble que cette erreur soit déclenchée car nous commençons avec le statut ok lors de l'instanciation, puis nous passons à la validation lorsque nous validons la version et l'état final en fonction de la réponse. Cependant, le cas d'utilisation lui-même semble raisonnable et, par conséquent, les changements d'état qui se produisent semblent également raisonnables.

@tundal45 pourriez-vous créer un twiddle ou un exemple d'application qui montre ce que vous pensez être une erreur incorrecte ?

@Blackening999 @tundal45 pouvez-vous réduire votre cas d'utilisation en un clin d'œil ?

@chancancode @Blackening999 Je vais essayer d'en poster un ici bientôt. Merci pour une réponse rapide.

@chancancode https://ember-twiddle.com/936d549b5625b0cf4f3c945d0ed04d3b?openFiles=components.button-with-state.js serait le twiddle mais je ne vois pas l'erreur que je vois dans l'application donc peut-être autre chose qui est la cause.

Je vois cela sur plusieurs propriétés calculées, dont l'une est un simple Ember.computed.or . Étant donné qu'aucune des suggestions de @manimis902 n'est applicable dans ce cas, quelle serait une solution de contournement appropriée ?

Comme @tharrington1 mentionne où se trouve le drapeau de la fonctionnalité mentionnée par @chancancode ?

@cbou pour autant que je sache ce drapeau n'existe pas

Je ne savais pas tout à fait comment gérer ces avis de dépréciation, ni si mon correctif était / est valide, mais je faisais une requête AJAX dans le hook de composant init() qui a déclenché un changement de valeur dans un autre propriété du service (pour suivre/afficher si vous accédez au serveur distant).

J'ai déplacé mon code de requête AJAX du hook de composant init() vers le hook de composant didRender() et cela semble avoir résolu mon avis de dépréciation.

@ lvl99 J'ai fait la même chose.

Nous nous efforçons de mettre à niveau notre projet d'entreprise vers Ember 2.12 à partir de 2.3. Dans notre projet, nous avons un module complémentaire de validation et un module complémentaire de composants de formulaire distinct. Le module complémentaire de validation fonctionne sur Ember.components pour générer des erreurs de validation et le module complémentaire de composants de formulaire affiche les erreurs générées par le module complémentaire de validation via un assistant. Les modules complémentaires sont bien trop compliqués pour partager le code source ; par conséquent, nous avons créé le twiddle suivant pour illustrer le cas auquel nous sommes confrontés.

L'exemple donné contient deux composants ( person-detail et address-detail ) qui sont chargés de générer leurs propres erreurs de validation. Les erreurs de validation générées par address-detail sont répercutées sur le composant contenant ( person-detail ) via une action lancée dans la propriété calculée errors . Les erreurs générées par chaque composant sont affichées dans un composant error-displayer à l'aide de l'assistant error-formatter . Le code fourni fonctionne comme prévu, comme vous pouvez le voir.

Toutefois; nous avons un avertissement de dépréciation comme suit : DEPRECATION: The error property ofis an Ember.Binding connected to validatable.errors.name , but Ember.Binding is deprecated. Consider using an alias computed property instead. [deprecation id: ember-metal.binding] See http://emberjs.com/deprecations/v2.x#toc_ember-binding for more details. Afin d'éviter cela; s'il vous plaît allez dans l'aide error-formatter et commentez la ligne numéro 9 et décommentez la ligne numéro 8 afin que nous fassions comme suggéré dans l'explication de l'avertissement.

Maintenant, nous arrivons au tristement célèbre Assertion Failed: You modified "error" twice on <Ember.Object:ember338> in a single render. It was rendered in "component:error-displayer" and modified in "component:error-displayer". This was unreliable and slow in Ember 1.x and is no longer supported. See https://github.com/emberjs/ember.js/issues/13948 for more details. Nous comprenons pourquoi nous obtenons cette erreur ; car le déclenchement d'une action dans la propriété calculée de address-detail s errors entraîne un recalcul de la propriété calculée de errors de person-detail et le contenu qui est déjà rendu est à l'origine de cette erreur . Voici ce que nous aimerions apprendre :

  1. Ember.Binding vs Ember.computed.alias fonctionne bien différemment en termes de phase de recalcul (re-rendu). Quelle est la différence exacte ? Suggérer d'utiliser ce dernier en remplacement du premier semble casser le code ; au moins pour notre cas.
  2. Le déclenchement d'une action à partir d'une propriété calculée est-il un problème ? Si oui; quelles sont les suggestions possibles pour l'éviter?
  3. Nous envisageons d'encapsuler le déclenchement d'une action dans une instruction Ember.run.scheduleOnce('afterRender', ...) . Est-ce la bonne voie à suivre ?
  4. Finalement; s'il vous plaît, revenez au code de rupture et tapez quelque chose dans n'importe quel champ ; et étonnamment, les composants sont restitués plusieurs fois ; nous pensons que cela pourrait être lié à un bogue.

FWIW, j'ai vu mes composants s'afficher à nouveau plus fréquemment que prévu dans certains cas. La recherche de la cause d'un rendu prend beaucoup de temps car elle est souvent synchronisée avec une boucle d'exécution. J'aimerais savoir s'il existe des raccourcis ou des astuces de débogage dans ce domaine.

Existe-t-il un moyen d'attraper ou de supprimer cette assertion sur les versions de débogage ? Nous avons localisé et corrigé ce problème via des refactors comme décrit ci-dessus dans la plupart des endroits, mais il y en a 1 ou 2 qui sont plutôt têtus. Dans un cas particulier, nous détruisons un objet, puis nous effectuons une transition. L'objet détruit (sur notre API) envoie une notification pusher pour décharger/détruire plusieurs autres objets.

Dans les versions de production, le nouveau rendu n'est pas un problème, car nous détruisons simplement l'objet, puis nous procédons à une transition de toute façon (donc toute la route est détruite). Cependant, l'affirmation sur les versions de développement est assez frustrante car elle nécessite une actualisation pour restaurer le site. Je comprends pourquoi nous obtenons l'erreur, mais c'est un refactor assez compliqué dans ce cas pour l'éviter, et dans tous les cas, cela n'a pas d'importance puisque tout l'itinéraire est détruit. Existe-t-il un moyen d'attraper/supprimer/changer cela en avertissement ? J'ai essayé un try/catch, ainsi que le gestionnaire d'erreurs de la route, mais aucun ne l'a récupéré.

@ feanor07 envoi d'une action depuis get qui invalide la propriété a qui a déjà été rendue est le reflux de données, avant que les liaisons avec un cycle ne détectent et sélectionnent silencieusement la direction vers l'avant comme gagnante, mais cela a un coût élevé si cela passait plusieurs choses et retourne à la source.

Fondamentalement, vous avez une dépendance cyclique et vous avez besoin que les données circulent, ne rendez pas l'erreur avant d'avoir exécuté la validation. Vous pouvez valider dans un composant parent qui génère le modèle et les erreurs pour rendre le formulaire à l'intérieur de son bloc.

@feanor07 Ember.run.scheduleOnce... n'a pas fonctionné, mais l'ajout d'un seul Ember.run.schedule("afterRender", () => { ... }); à la propriété set indiquée en premier par la trace de la pile a éliminé de nombreux messages d'erreur qui se sont produits en cascade après le premier.

@neilthawani qui peut masquer l'erreur, mais cela ne résout pas nécessairement le problème. L'erreur est destinée à indiquer que vous définissez une valeur deux fois alors que vous ne devriez probablement la définir qu'une seule fois. En mettant l'un des set dans schedule , vous retardez simplement le deuxième set afin qu'il se produise dans une boucle d'exécution différente. Vous n'avez pas résolu le problème central du rendu deux fois alors que vous n'avez besoin de rendre qu'une seule fois, vous venez de faire croire à Ember qu'il ne savait pas qu'il y avait un problème car maintenant les rendus se produisent dans des boucles d'exécution distinctes.

@elwayman02 Euh oh. Merci. Fondamentalement, j'ai complètement raté le point.

Edit : Après avoir lutté avec, j'ai inséré quelques afterRenders que ce avec quoi j'étais à l'aise. Nous avons un gestionnaire click sur l'un de nos composants de visualisation de données qui bascule une info-bulle. Définir l'indicateur isDisplaying dans un Ember.run.schedule("afterRender", () => { ... }); nous a permis de déboguer le vrai problème, qui était en fait un retour en arrière dans le contrôleur appelant à la fois le composant de visualisation de données et le composant d'info-bulle.

tl;dr : Je ne l'ai pas gardé là-dedans (j'ai eu une erreur Maximum call stack size exceeded une fois aussi), mais son utilisation a été utile pour le débogage jusqu'à ce que le vrai problème soit découvert.

Message d' @GavinJoyce ci-dessus est en fait incluse dans Ember 2.11. Il a également été suggéré que passer directement à 2.11 pourrait être utile.

Les gars, j'ai besoin d'aide : cette erreur apparaît lorsque j'essaie d'utiliser une propriété de modèle qui "appartient à" une autre. J'ai créé un projet vierge, et il montre toujours la même chose. Qu'est-ce que je fais mal?

De plus, sur mon back-end, j'utilise .Net Core avec l'API JSON .Net Core (https://github.com/Research-Institute/json-api-dotnet-core) - en suivant leurs instructions.

Le rendu de l'interface utilisateur est cassé à ce stade, mais les données se chargent et je peux voir les valeurs souhaitées.

    // Profile Model:
    import DS from 'ember-data';
    export default DS.Model.extend({
        'firstName': DS.attr(),
        'lastName': DS.attr(),
        'applicationUser': DS.attr(),
        'contactProfile': DS.belongsTo('address', {
            async: true
        }),
        'companyProfile': DS.belongsTo('address'),
        'companyMailingAddress': DS.belongsTo('address'),
        "companyPhysicalAddress": DS.belongsTo('address')
    });

    // Address Model:
    import DS from 'ember-data';
    export default DS.Model.extend({
        'address1': DS.attr(),
        'address2': DS.attr(),
        'city': DS.attr(),
        'state': DS.attr(),
        'zipCode': DS.attr(),
        'country': DS.attr(),
        'website': DS.attr(),
        'phoneNumber1': DS.attr(),
        'phoneExtension1': DS.attr(),
        'phoneNumber2': DS.attr(),
        'phoneExtension2': DS.attr(),
        'email': DS.attr(),
    });
    // Adapter settings
    import DS from 'ember-data';

    export default DS.JSONAPIAdapter.extend({
        namespace: 'api/json',
    });
    DS.JSONAPISerializer.reopen({
        keyForAttribute(key) {
            return key;
        },
        keyForRelationship(key) {
            return key;
        }
    });
    // Route
    import Ember from 'ember';

    export default Ember.Route.extend({
        model() {
            return Ember.RSVP.hash({
                profile: this.store.findRecord('profile', 1)
            });
        }
    });

    // Template
   {{model.profile.contactProfile.address1}}

et l'erreur que j'obtiens :
Échec de l'assertion : vous avez modifié « model.profile.contactProfile » deux fois sur@model:profile::ember543:1> en un seul rendu. Il a été rendu dans " template:fuels-ember/internal/profile/template.hbs " et modifié dans " template:fuels-ember/internal/profile/template.hbs ". Ce n'était pas fiable et lent dans Ember 1.x et n'est plus pris en charge. Voir https://github.com/emberjs/ember.js/issues/13948 pour plus de détails.

PS: j'ai essayé d'utiliser la méthode Ember.computed pour obtenir la propriété, et cela semble fonctionner. Est-ce obligatoire ?

Mise à jour : j'ai également découvert que les données se chargent très bien à l'intérieur d'un assistant {{#each}}, mais pas directement sur le modèle.

@lbarsukov
C'est peut-être lié à https://github.com/emberjs/data/issues/5023 où un retour en arrière est causé par des relations dans votre réponse jsonapi ayant un ensemble de propriétés links .

C'était le problème pour moi, qui a commencé après Ember Data 2.13.2. Essayez d'utiliser ember-data : 2.13.2 pour voir si cela résout votre problème.

@daniel-de-wit Bravo pour le maître ici - cela fonctionne réellement. Il fait maintenant ce dont j'ai besoin et j'en suis satisfait.

@lbarsukov @daniel-de-wit Nous avons publié une nouvelle version des données de braise qui résout ce problème.

@lbarsukov Je pense que cela a à voir avec vos relations définies. Il y a de fortes chances qu'un (ou plusieurs) des belongsTo soit un hasMany .

Supposons que vous ayez deux modèles, Question et Réponse. Si vous retournez 10 réponses à la question, mais que chaque sérialiseur de question fait référence à sa réponse, vous _devez_ définir correctement la relation.

// Question Model:
    export default DS.Model.extend({
        'answers': DS.hasMany('answers'), // if you never reference question.answers you can omit this
        ...
    });

// Answer Model:
    export default DS.Model.extend({
        'question': DS.belongsTo('question'),
        ...
    });

Lorsque les données rencontrent la définition de plusieurs paires question/réponse, en s'attendant à une relation 1-1 là où il n'y en a pas, cela en déduit que la question a été modifiée au milieu du rendu.

Dès le message initial, certains crochets ont été mentionnés :

C'est un exemple assez extrême, mais il illustre le problème. Outre init, didInitAttrs, didReceiveAttrs, willInsertElement et willRender se produisent également de manière synchrone pendant le processus de rendu. De plus, le retour en arrière est souvent un problème résultant du comportement des propriétés liées dans les deux sens.

Pourquoi les crochets didInsertElement et didRender fonctionnent-ils comme un charme mais les autres crochets échouent avec twice render erreur

@BenjaminHorn @ Blackening999 @Dhaulagiri @DingoEatingFuzz @ Gaurav0 @GavinJoyce @Redsandro @TRMW @ Turbo87 @aklkv @alidcastano @backspace @bdiz @bgentry @bjornharrtell @bryanhickerson @buschtoens @caseklim @cbou @chancancode @danaoira @ daniel-de-esprit @fivetanley @fotinakis @gabrielgrant @ghost @jakesjews @janmisek @joukevandermaas est-ce toujours un problème, peut-être devrions-nous fermer, qu'en pensez-vous ?

J'ai corrigé toutes les instances de l'erreur dans mon application.

Chaque fois que j'ai rencontré cela, j'ai pu réorganiser les choses pour que cela ne se produise plus, donc je pense que je peux fermer.

Oui, veuillez fermer

fin d'une époque

??

Désolé de soulever un vieux problème.

Disons par exemple que je rends

{{this.myBool}}

et l'erreur est Error: Assertion Failed: You modified "myBool" twice

Je peux corriger l'erreur en la changeant en :

{{if this.myBool true false}}

De même, si une liaison de nom de classe est à l'origine du problème

Je peux changer:

classNameBindings: ['myBool']

à

classNameBindings: ['myBool:yes:no']

Si je peux faire taire l'avertissement comme ça, pourquoi Ember ne peut-il pas le gérer pour moi ?

Voici le code de démonstration que j'utilisais :

https://ember-twiddle.com/db7f6e382bd0b1de91447881eebb62a5?openFiles=templates.components.my-component.hbs%2C

Aucune de ces choses ne « résout » le problème. C'est soit que vous êtes passé en mode production, soit qu'il y a des bugs dans le code d'assertion/détection. Dans tous les cas, vous devez fixer le côté qui attribue/définit la valeur, pas le côté qui la consomme.

D'accord. Merci. Je comprends le problème de retour en arrière décrit dans ce message original car il a un set explicite

Mais dans mon twiddle de démonstration, il n'y a pas de set pour autant que je sache.

_Edit_ Cela s'est mal passé, je veux dire qu'il n'y a pas de set provenant d'une partie _subsequent_ du modèle comme dans l' exemple

Hm, je ne reçois pas l'erreur dans le twiddle, quelle est la séquence de clics que je dois faire ?

Cliquez sur Ouvrir, puis sur Fermer. Mais le bouton de fermeture du composant enfant cédé, pas le parent.

Je vois, le problème est que pendant le démontage, focusOut est appelé sur le composant qui appelle set sur une propriété déjà rendue. Je ne sais pas à 100% comment le composant perd le focus et la sémantique de synchronisation. Je suis à peu près sûr que les variantes que vous avez essayées perturbent simplement le système de suivi et masquent le problème sous-jacent. Suivons-le dans un nouveau numéro ? Je ne sais pas si c'est une question valable, mais faisons l'enquête là-bas.

Cette page vous a été utile?
0 / 5 - 0 notes