React: Déprécier `isMounted`

Créé le 14 nov. 2015  ·  48Commentaires  ·  Source: facebook/react

isMounted est déjà indisponible sur les classes ES6, et nous avons déjà un avertissement disant que nous "pourrons" les supprimer, mais nous n'avons pas réellement de problème github pour les déprécier. D'après nos discussions d'aujourd'hui, nous sommes essentiellement d'accord sur le fait que nous allons commencer à nous éloigner de isMounted et à le déprécier. Nous devons encore trouver de bonnes histoires autour des promesses (et des cas d'utilisation associés).

Cette question est de suivre les progrès vers cet objectif.

Pour le contexte, veuillez lire :

Commentaire le plus utile

Cette méthode simple peut être utilisée pour ajouter une annulation à n'importe quelle promesse

const makeCancelable = (promise) => {
  let hasCanceled_ = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then((val) =>
      hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
    );
    promise.catch((error) =>
      hasCanceled_ ? reject({isCanceled: true}) : reject(error)
    );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled_ = true;
    },
  };
};

EDIT : mis à jour pour l'exactitude/l'exhaustivité.

COMMENT UTILISER

const somePromise = new Promise(r => setTimeout(r, 1000));

const cancelable = makeCancelable(somePromise);

cancelable
  .promise
  .then(() => console.log('resolved'))
  .catch(({isCanceled, ...error}) => console.log('isCanceled', isCanceled));

// Cancel promise
cancelable.cancel();

Tous les 48 commentaires

Je ne suis pas d'accord avec ça. Les promesses ES6 en particulier ne peuvent pas être annulées de manière fiable sur componentWillUnmount , donc supprimer le seul moyen de vérifier si le composant est monté avant setState ou une autre action ouvre la voie à de nombreux bogues asynchrones difficiles à tracer.

@yaycmyk Ainsi la ligne :

Nous devons encore trouver de bonnes histoires autour des promesses (et des cas d'utilisation associés).

Veuillez lire les problèmes de fond que j'ai énumérés, en particulier : https://github.com/facebook/react/issues/2787#issuecomment -68738793

J'ai lu les commentaires. Je trouve juste les problèmes insolubles.

Pourquoi les promesses ne peuvent-elles pas être annulées de manière fiable ? Des sources/preuves/exemples ?

Le lundi 16 novembre 2015, Evan Jacobs [email protected] a écrit :

Je ne suis pas d'accord avec ça. Les promesses ES6 en particulier ne peuvent pas être fiables
annulé sur componentWillUnmount, supprimant donc le seul moyen de vérifier si
le composant est monté avant setState ou une autre action ouvre le
façon pour beaucoup de bogues asynchrones difficiles à tracer.

@nvartolomei Regardez la spécification de la promesse ES6.

C'est un objectif à plus long terme, pas quelque chose qui se passe immédiatement. Mais nous voulons suivre la planification et les discussions en un seul endroit et non à travers les commentaires dans chaque numéro lorsque cela se produit. Nous sommes conscients du problème des promesses actuellement non annulables, ce qui est l'une des principales raisons pour lesquelles nous ne l'avons pas déjà fait.

@yaycmyk Pour simplifier à l'excès un problème très complexe... les commentaires disent... utiliser isMounted pour éviter setState pour les composants non montés ne résout pas réellement le problème que le setState avertissement setState à la suite d'une promesse est de toute façon un peu un anti-modèle, car cela peut provoquer des conditions de concurrence qui n'apparaîtront pas nécessairement lors des tests. Nous voulons donc nous en débarrasser et trouver une recommandation de "meilleure pratique" pour l'utilisation des promesses avec React.

Je suis d'accord que les problèmes sont un peu impénétrables, mais c'est en grande partie parce qu'il s'agit d'un problème complexe que nous sommes encore en train de résoudre et pour lequel nous n'avons pas encore de réponse prédéfinie.

appeler setState à la suite d'une promesse est de toute façon un peu anti-modèle, car cela peut provoquer des conditions de concurrence qui n'apparaîtront pas nécessairement dans les tests

Nous pouvons être d'accord pour ne pas être d'accord sur ce point. Il y a des moments où le contenu est récupéré de manière asynchrone et vous ne voulez pas avoir à passer par un rendu à grande échelle pour faire apparaître ce contenu une fois qu'il est résolu. Je l'utilise spécifiquement dans une implémentation de vue de table infinie où un rendu virtuel complet serait inutile.

Vous ne pourrez peut-être pas annuler une promesse, mais vous pouvez lui faire déréférencer le composant lors du démontage, comme suit :

const SomeComponent = React.createClass({
    componentDidMount() {
        this.protect = protectFromUnmount();

        ajax(/* */).then(
            this.protect( // <-- barrier between the promise and the component
                response => {this.setState({thing: response.thing});}
            )
        );
    },
    componentWillUnmount() {
        this.protect.unmount();
    },
});

La distinction importante est que lorsque this.protect.unmount() est appelé dans componentWillUnmount , tous les rappels sont déréférencés, ce qui signifie que le composant est déréférencé, puis lorsque la promesse se termine, il appelle simplement un no-op. Cela devrait empêcher toute fuite de mémoire liée aux promesses de références de composants non montés. source pour protectFromUnmount

Cette méthode simple peut être utilisée pour ajouter une annulation à n'importe quelle promesse

const makeCancelable = (promise) => {
  let hasCanceled_ = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then((val) =>
      hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
    );
    promise.catch((error) =>
      hasCanceled_ ? reject({isCanceled: true}) : reject(error)
    );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled_ = true;
    },
  };
};

EDIT : mis à jour pour l'exactitude/l'exhaustivité.

COMMENT UTILISER

const somePromise = new Promise(r => setTimeout(r, 1000));

const cancelable = makeCancelable(somePromise);

cancelable
  .promise
  .then(() => console.log('resolved'))
  .catch(({isCanceled, ...error}) => console.log('isCanceled', isCanceled));

// Cancel promise
cancelable.cancel();

La liste des moyens de sup-up-up ES6 promet de les rendre annulables est d'ailleurs le point. L'intention devrait être de fournir une solution qui fonctionne AVEC la spécification plutôt que d'essayer de travailler AUTOUR de la spécification.

Je suis d'accord. Au lieu de simplement vérifier si le composant est toujours monté lorsque nous recevons le résultat de la promesse, nous devons recourir à toutes sortes de magie afin de pouvoir "délier" notre promesse du composant dans lequel il est censé définir son résultat, en luttant clairement contre la façon dont les promesses sont conçus.
Pour moi, cela ressemble à une ingénierie excessive d'une solution où un simple test est le moyen le plus simple de résoudre ce problème.

Nous pouvons continuer à vérifier simplement en :

React.createClass(function() {
  componentDidMount: function() {
    this._isMounted = true;

    ajax(/* */).then(this.handleResponse);
  }

  handleResponse: function(response) {
    if (!this._isMounted) return; // Protection

    /* */
  }

  componentWillUnmount: function() {
    this._isMounted = false;
  }
});

C'est bien sûr mon opinion, mais il me semble que le chargement de données asynchrone avec une promesse à l'intérieur d'un composant React est un scénario si courant qu'il devrait être couvert par React, au lieu d'avoir à écrire notre propre code passe-partout.

Le problème est que pour suivre le véritable état de montage, nous devons ajouter un écouteur lorsque la réaction terminera le processus de montage DOM dans chaque composant (le même, qui attache componentDidMount, s'il est défini), mais cela affectera les performances, car nous n'avons pas besoin le jachère partout. Le composant n'écoute pas le montage DOM prêt par défaut car componentDidMount n'est pas défini.

Et si setState pouvait recevoir une promesse enchaînée qui résout les changements d'état souhaités ? Si le composant se démonte, s'il y a des promesses en attente, leur résultat final est ignoré.

@istarkov joli motif, comme ça ! Voici une API légèrement modifiée pour cela :

// create a new promise
const [response, cancel] = await cancelable(fetch('/api/data'));

// cancel it
cancel();

Puisque je suis nouveau dans React et que je lis des documents, juste pour jeter ceci : l'astuce Load Initial Data via Ajax utilise .isMounted() , donc le site Web n'est pas d'accord avec le site Web. Ce serait formidable de voir une astuce complète sur la façon d'annuler le chargement initial dans componentWillUnmount , peut-être en utilisant le modèle de

@dtertman Corrigé dans https://github.com/facebook/react/pull/5870 , sera en ligne lorsque les documents seront sélectionnés.

@jimfb merci, je ne sais pas comment j'ai raté ça dans la recherche.

@istarkov ne sait pas si c'était intentionnel mais votre makeCancelable ne gère pas si la promesse originale échoue. Lorsque la promesse d'origine est rejetée, aucun gestionnaire n'est appelé.

Cela ne semble pas idéal car vous pouvez toujours vouloir gérer une erreur sur la promesse d'origine.

Voici ma proposition pour un makeCancelable qui gère un rejet dans la promesse d'origine :

const makeCancelable = (promise) => {
  let hasCanceled_ = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then((val) =>
      hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
    );
    promise.catch((error) =>
      hasCanceled_ ? reject({isCanceled: true}) : reject(error)
    );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled_ = true;
    },
  };
};

Je ne sais pas où je me situe si faire des promesses annulables est une bonne idée, mais si nous allons faire des promesses annulables, nous devons préserver le comportement sous-jacent :).

@vpontis : +1:

@istarkov, votre message d'origine est référencé ici : https://facebook.github.io/react/blog/2015/12/16/ismount-antipattern.html

Voulez-vous mettre à jour votre message ou dois-je envoyer un message à l'auteur du message ?

@vpontis Merci, je vais réparer ! (https://github.com/facebook/react/pull/6152)

Hey @jimfb , amusant de te

Autre correction de bug dans la fonction makeCancelable : cela peut provoquer un UnhandledPromiseRejectionWarning dans les versions récentes des nœuds (en particulier lors de l'exécution de tests avec une nouvelle version de nœud). L'un des changements apportés au nœud 6.6.0 est que tous les rejets de promesses non @vpontis avait des then et catch sur la même promesse de base. Effectivement, cela crée _deux_ promesses, une qui ne gère que le succès et une qui ne gère que les erreurs. Cela signifie que s'il y a une erreur, la première promesse sera considérée par le nœud comme un rejet de promesse non géré.

Le correctif est assez simple : il suffit d'enchaîner les deux appels pour qu'il fasse une promesse avec à la fois un gestionnaire de réussite et d'erreur. Voici le code fixe :

const makeCancelable = (promise) => {
  let hasCanceled_ = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise
      .then((val) =>
        hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
      )
      .catch((error) =>
        hasCanceled_ ? reject({isCanceled: true}) : reject(error)
      );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled_ = true;
    },
  };
};

@alangpierce C'est très proche de la correction, mais pas tout à fait ; si resolve() ou reject() lancent

La solution consiste à utiliser le modèle .then(onFulfilled, onRejected) :

const makeCancelable = (promise) => {
  let hasCanceled_ = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then(
      (val) => hasCanceled_ ? reject({isCanceled: true}) : resolve(val),
      (error) => hasCanceled_ ? reject({isCanceled: true}) : reject(error)
    );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled_ = true;
    },
  };
};

Cette solution makeCancelable n'est-elle pas la même chose que l'appel isMounted() lorsque l'on examine le point 3 pour savoir pourquoi isMounted() est déconseillé :

Appel de setState lorsqu'un composant est complètement démonté.
C'est une indication forte qu'un rappel asynchrone n'est pas correctement nettoyé. Malheureusement, les API JS traditionnelles permettent d'éviter très facilement de nettoyer les rappels asynchrones suspendus.

Un rappel n'est pas un gros problème. Cependant, ce rappel s'accroche aux objets et aux rappels intermédiaires, aux promesses et aux abonnements. Si beaucoup de vos composants font cela, vous rencontrerez rapidement des problèmes de mémoire

makeCancellable crée simplement une autre promesse qui finit par contenir une référence à des fonctions qui contiennent une référence au composant. la solution makeCancellable déplace simplement la propriété booléenne isMounted dans la promesse.

afin de résoudre le problème de GC, vous devez annuler quelque chose lorsque cancel() est appelé. sinon, vous avez toujours une chaîne de référence du processus asynchrone au composant.

class CancellableDeferred {
  constructor(request) {
    this.deferred = $.Deferred();

    request.then((data) => {
      if (this.deferred != null) {
        this.deferred.resolve(data);
      }
    });

    request.fail((data) => {
      if (this.deferred != null) {
        this.deferred.reject(data);
      }
    });
  }

  cancel() {
    this.deferred = null;
  } 

  promise() {
    return this.deferred.promise();
  }
}

-> c'est comme ça que je le ferais avec des objets différés jQuery. Je ne connais pas vraiment l'API Promise, donc je ne sais pas à quoi cela ressemblerait. De plus, cela ne rejette pas le différé lorsque cancel() a été appelé et que le différé n'a pas été résolu. Les gens ont probablement une opinion différente sur la façon dont cela devrait fonctionner.

donc la chaîne ressemble à ceci:

Requête AJAX -> Fermeture -> CancellableDeferredInstance -> JQuery Deferred -> Component

puis après annulation, cela ressemble à ceci:

Requête AJAX -> Fermeture -> CancellableDeferredInstance / référence d'objet maintenant null/ JQuery Deferred -> Component

donc la demande AJAX n'empêche plus le composant d'être GCd [en supposant que je n'ai pas foiré l'implémentation quelque part en tenant accidentellement une référence à différé. ouai fermetures....]

Salut @benmmurphy , je ne suis pas très familier avec la compilation de déchets JS et cela peut fonctionner différemment avec React, mais j'ai une compréhension différente.

makeCancellable permet à un composant React d'être récupéré lorsqu'il est démonté. Je vais t'expliquer.

makeCancellable crée simplement une autre promesse qui finit par contenir une référence à des fonctions qui contiennent une référence au composant. la solution makeCancellable déplace simplement la propriété booléenne isMounted dans la promesse.

Sans makeCancellable :

handleError() {
  if (this.isMounted()) {
    console.log('ERROR')
  }
}

Avec makeCancellable :

promise.then(...).fail((reason) => {
  if (reason.isCancelled) return;
  console.log('ERROR');
})

Sans makeCancellable vous avez toujours une référence à this donc le composant ne peut pas être récupéré lors de son démontage. Mais dans l'autre cas, le gestionnaire d'échec de la promesse annulable est appelé dès que le composant est démonté, vous n'avez donc plus de références qui traînent.

@vpontis

J'ai du code nodejs qui illustre le problème. Le composant Foo ne sera GC qu'une fois que le rappel asynchrone resolve a été défini sur null. Par exemple, disons que vous lancez une requête ajax qui prend 30 secondes à résoudre, puis le composant est démonté. Ensuite, le composant ne sera pas GCd pendant 30s. C'est l'un des problèmes qu'ils essaient de résoudre en désapprouvant isMount().

npm install promise
npm install weak

node --expose-gc gc.js
first gc Foo {}
after first gc Foo {}
after resolve = null Foo {}
foo gc'd
after second gc {}

https://gist.github.com/benmmurphy/aaf35a44a6e8a1fbae1764ebed9917b6

ÉDITER:

désolé de vous avoir dépassé, mais la première fois que j'ai lu le message, je n'ai pas compris le point que vous essayiez de faire valoir, mais maintenant je pense que oui. Je pense que ce que vous essayez de dire, c'est que parce que le rappel d'erreur ne contient pas de référence au composant (ou ne suit pas une référence au composant), le composant n'est pas considéré comme référencé par la promesse. C'est en fait vrai. Eh bien, la première partie est vraie. Cependant, il y a des problèmes avec ce raisonnement :

1) même si le gestionnaire d'erreurs de votre exemple n'a pas de référence au composant, le rappel then() fera généralement. Par exemple, le handle then fera généralement this.setState(...) .
2) même si le gestionnaire d'erreurs de votre exemple n'a pas de référence au composant que la plupart des gestionnaires d'erreurs auront. par exemple, ils feront quelque chose comme :

promise.then(...).fail((reason) => {
  if (reason.isCancelled) return;
  console.log('ERROR');

  this.setState({error: true});
})

3) même si nous savons que le code ne suivra pas le rappel then() et que nous savons qu'il quittera la fonction après avoir vérifié la variable isCancelled , le GC ne le sait pas.

et avant que quiconque n'utilise mon exemple ou quelque chose basé sur celui-ci, assurez-vous de tester qu'il fonctionne correctement. je n'ai pas encore testé le mien et ça ne me surprendrait pas si ça ne fonctionnait pas car j'ai fait une erreur stupide :/

en termes de promesse API, cela fonctionne pour moi dans nodejs en termes de GC. cependant, je préférerais ne pas avoir les paramètres _resolve , _reject près des fermetures parce que je ne sais pas si cela est garanti de fonctionner selon les spécifications JS ou si cela fonctionne simplement car le nœud effectue des optimisations. Une implémentation peut-elle capturer toutes les variables visibles ou uniquement les variables référencées dans la fermeture ? Je ne sais pas, peut-être que quelqu'un qui comprend réellement JS peut intervenir et expliquer :)

var makeCancelable = (promise) => {
  let resolve;
  let reject;

  const wrappedPromise = new Promise((_resolve, _reject) => {
    resolve = _resolve;
    reject = _reject;

    promise.then((val) => {
       if (resolve != null) resolve(val)
    });
    promise.catch((error) => {
       if (reject != null) reject(error)
    });
  });

  return {
    promise: wrappedPromise,
    cancel() {
      resolve = null;
      reject = null;
    },
  };
};

La fonction isMounted sera-t-elle supprimée dans 16.0 ?

Suggestion de petite amélioration avec le code @istarkov :

const makeCancelable = (promise) => {
    let hasCanceled_ = false
    promise.then((val) =>
        hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
    )
    .catch((error) =>
        hasCanceled_ ? reject({isCanceled: true}) : reject(error)
    )

    return {
        promise,
        cancel() {
            hasCanceled_ = true
        }
    }
}

C'est juste que la nouvelle promesse est redondante.

C'est juste que la nouvelle promesse est redondante.

@BnayaZil Vous appelez des fonctions resolve et reject , mais on ne sait pas d'où elles viennent. Vouliez-vous dire Promise.resolve et Promise.reject ? Dans ce cas, vous retourneriez toujours une nouvelle promesse.

Il y a quelques jours, une nouvelle API a été ajoutée à la spécification DOM qui vous permet d'annuler les requêtes fetch(). Cette API n'est encore implémentée dans aucun navigateur, mais j'ai créé un polyfill pour elle disponible sur NPM était "abortcontroller-polyfill". Le polyfill fait essentiellement la même chose que le code publié par @istarkov mais vous permet de passer sans modification de code à la véritable API du navigateur une fois qu'elle est implémentée.

Détails ici :
https://mo.github.io/2017/07/24/abort-fetch-abortcontroller-polyfill.html

Étant donné que React.createClass n'existe plus dans React 16 et que le nouveau package create-react-class inclut un message d'obsolescence clair pour isMounted , je vais clore cela.

Je suis d'accord avec @benmmurphy que la solution de @istarkov est effectivement la même que l'utilisation de isMounted() car elle ne résout pas le problème de la récupération de place.

La solution de @benmmurphy est plus proche mais annule les mauvaises variables afin que les gestionnaires de promesses ne soient pas déréférencés.

La clé passe une fonction vers le haut à travers la fermeture qui déréférence les gestionnaires :

const makeCancelable = promise => {
  let cancel = () => {};

  const wrappedPromise = new Promise((resolve, reject) => {
    cancel = () => {
      resolve = null;
      reject = null;
    };

    promise.then(
      val => {
        if (resolve) resolve(val);
      },
      error => {
        if (reject) reject(error);
      }
    );
  });

  wrappedPromise.cancel = cancel;
  return wrappedPromise;
};

De plus amples explications sur les raisons pour lesquelles cette solution permet le ramasse-miettes et non les solutions précédentes peuvent être trouvées ici .

Je suis allé de l'avant et j'ai transformé cela en un package npm, pouvant être supprimé . Et puisque le cas d'utilisation est React, j'ai créé un composant HOC qui suit les promesses et les annule lorsque le composant est démonté, trashable-react .

Edit: mon mauvais, je viens de regarder @hjylewis thrashable , et cela annule également les promesses. Toujours le modèle ci-dessous est l'OMI une petite amélioration.

Aucune de ces solutions n'annule les promesses, qui peuvent être annulées sans aucune prolongation en absorbant une promesse éternelle.

function makeCancelable(promise) {
  let active = true;
  return {
    cancel() {active = false},
    promise: promise.then(
      value => active ? value : new Promise(()=>{}),
      reason => active ? reason : new Promise(()=>{})
    )
  }
}

// used as above:

const {promise, cancel} = makeCancelable(Promise.resolve("Hey!"))

promise.then((v) => console.log(v)) // never logs
cancel()

vivre ici

Il peut y avoir des subtilités à aplanir concernant la GC et le café n'a pas encore commencé, mais ce modèle garantit que la promesse retournée est vraiment annulée et qu'elle peut être évitée (je l'ai mise en œuvre dans le passé).

@pygy Merci pour la réponse !

Malheureusement, votre solution ne permet toujours pas la collecte des ordures. Vous venez essentiellement de réécrire la solution de @istarkov qui utilise un conditionnel.

Vous pouvez tester cela facilement en déposant cette implémentation dans la corbeille et en exécutant les tests (le test de récupération de place échoue).

Votre implémentation ne parvient pas non plus à gérer correctement les erreurs.

Nous sommes en 2018, y a-t-il une approche encore meilleure que celle mentionnée ci-dessus ?

oui vous pouvez utiliser certains frameworks de navigation qui ont une documentation deux fois plus volumineuse que la réactivité native mais qui est très professionnelle

Ces extraits pour "annuler" une promesse ne sont pas si bons à mon humble avis. Les promesses annulées ne seront toujours pas résolues tant que la promesse d'origine ne sera pas résolue. Ainsi, le nettoyage de la mémoire ne se produira que si vous utilisiez simplement une astuce isMounted.

Un wrapper de promesse annulable approprié devrait utiliser une deuxième promesse et Promise.race. c'est- Promise.race([originalPromise, cancelationPromise]) dire

La solution de @benmmurphy est plus proche mais annule les mauvaises variables afin que les gestionnaires de promesses ne soient pas déréférencés.

Je pense que ma solution fonctionne mais je n'en sais pas assez sur les promesses du runtime javascript pour en être sûr. Si vous exécutez la solution sous le nœud dans votre faisceau de test, la valeur est correctement GC. Ma solution a attribué les fonctions de résolution/rejet à une portée plus élevée, puis a annulé ces valeurs lorsque l'annulation a été appelée. Cependant, les fonctions étaient toujours disponibles dans la portée inférieure mais non référencées. Je pense que les moteurs javascript modernes ne capturent pas les variables dans une fermeture à moins qu'elles ne soient référencées. Je pense que c'était un gros problème où les gens créaient accidentellement des fuites DOM parce qu'ils faisaient des trucs comme : var element = findDOM(); element.addEventListener('click', function() {}); et l'élément serait référencé dans la fermeture même s'il n'a pas été utilisé dans la fermeture.

@hjylewis @benmmurphy pourquoi devons-nous déréférencer les gestionnaires ?? après l'exécution des gestionnaires, le ramassage des ordures se produit de toute façon, n'est-ce pas ??

Ces extraits pour "annuler" une promesse ne sont pas si bons à mon humble avis. Les promesses annulées ne seront toujours pas résolues tant que la promesse d'origine ne sera pas résolue. Ainsi, le nettoyage de la mémoire ne se produira que si vous utilisiez simplement une astuce isMounted.

Un wrapper de promesse annulable approprié devrait utiliser une deuxième promesse et Promise.race. c'est- Promise.race([originalPromise, cancelationPromise]) dire

@hjylewis et le mien travaillez-vous réellement, vous pouvez le vérifier avec un nœud faible. mais en les regardant à nouveau, je suis d'accord qu'aucun d'eux n'est un code de promesse écrit idiosyncratique. en tant qu'utilisateur de promesse, vous vous attendriez probablement à ce qu'une promesse « annulée » se résolve dans l'état rejeté et aucun d'eux ne le fait. cependant, peut-être dans le cas d'un composant, c'est une solution qui serait plus facile à utiliser car vous n'avez pas à écrire de code supplémentaire pour ignorer le gestionnaire de rejet.

Je pense qu'une promesse rejetable idiosyncratique utiliserait Promise.race([]) pour construire une promesse annulable. cela fonctionne car lorsqu'une promesse est résolue, les rappels en attente sont supprimés, de sorte qu'il n'y aurait plus de chaîne de référence du réseau du navigateur à votre composant car il n'y aurait plus de référence entre la promesse de course et le composant.

Je suis curieux de savoir s'il est d'une manière ou d'une autre possible d'utiliser Promise.all() avec ces promesses annulables et d'éviter les erreurs non détectées dans la console du navigateur ... car je ne suis capable de détecter que la première erreur d'annulation, les autres restent non détectées.

Nous sommes en 2018, y a-t-il une approche encore meilleure que celle mentionnée ci-dessus ?

Toute meilleure approche pour annuler l'exécution d'une promesse, c'est-à-dire setTimeout, appels API, etc. Nous sommes en 2019 😭 😞

Il y a un fil d'annulation de promesse en cours sur TC39, (je pense) c'est pertinent ici (peut-être .. pas sûr)
https://github.com/tc39/proposal-cancellation/issues/24

Toute meilleure approche pour annuler l'exécution d'une promesse, c'est-à-dire setTimeout, appels API, etc. Nous sommes en 2019 😭 😞

Cherchons-nous quelque chose comme

const promise = new Promise(r => setTimeout(r, 1000))
  .then(() => console.log('resolved'))
  .catch(()=> console.log('error'))
  .canceled(() => console.log('canceled'));

// Cancel promise
promise.cancel();
Cette page vous a été utile?
0 / 5 - 0 notes