try-catch en javascript… n'est-ce pas une bonne pratique?

69

Il existe une disposition pour le blocage try-catch en javascript . Bien qu'en Java ou dans toute autre langue, la gestion des erreurs soit obligatoire, je ne vois personne les utiliser en javascript dans une plus large mesure. N'est-ce pas une bonne pratique ou simplement nous n'en avons pas besoin en javascript?

akp
la source
2
While in java or *any other language* it is mandatory to have error handling...- Pas vraiment. Java, oui, mais il y a beaucoup de langages qui n'insistent pas sur try-catch (comme C #).
Jim G.
C'est parce que vous ne pouvez pas les utiliser dans un environnement asynchrone. Je les utilise souvent par le code de synchronisation par un niveau d'abstraction plus faible, par exemple en transformant quelque chose en quelque chose, etc ...
inf3rno
Je parie que vous voyez plus d'essais dans le code côté serveur que le code côté client. La plupart du code côté cliend que vous connaissez ne fait rien d’important. Je parierais qu'il est plus important de minimiser les Ko en aval que de récupérer après chaque erreur - dans la plupart des applications et dans les circonstances propres à un navigateur.
svidgen
Il existe un autre moyen d'éviter d'essayer d'attraper en utilisant peut-être et soit (monades) nous avons eu un scrapper Web écrit en noeud. Nous avons réussi à supprimer toutes les captures d’essais.
user93

Réponses:

66

Il faut éviter les throwerreurs comme moyen de faire passer les conditions d'erreur dans les applications.

La throwdéclaration ne devrait être utilisée que "Pour que cela ne se produise jamais, plantez et brûlez. Ne récupérez jamais de façon élégante"

try catch Cependant, il est utilisé dans des situations où des objets hôtes ou ECMAScript peuvent générer des erreurs.

Exemple:

var json
try {
    json = JSON.parse(input)
} catch (e) {
    // invalid json input, set to null
    json = null
}

Dans la communauté node.js , il est recommandé de transmettre les erreurs dans les rappels (car les erreurs ne se produisent que pour les opérations asynchrones) en tant que premier argument.

fs.readFile(uri, function (err, fileData) {
    if (err) {
        // handle
        // A. give the error to someone else
        return callback(err)
        // B. recover logic
        return recoverElegantly(err)
        // C. Crash and burn
        throw err
    }
    // success case, handle nicely
})

Il y a aussi d'autres problèmes, comme essayer / attraper, c'est très cher et c'est moche et ça ne fonctionne tout simplement pas avec les opérations asynchrones.

Donc, puisque les opérations synchrones ne doivent pas générer d'erreur et que cela ne fonctionne pas avec les opérations asynchrones, personne n'utilise try catch, à l'exception des erreurs renvoyées par des objets hôtes ou par ECMAScript.

Raynos
la source
2
Je n'irais pas jusqu'à dire que personne n'utilise try catch, c'est le mauvais outil pour le travail dans la plupart des cas. Quand il y a vraiment des circonstances exceptionnelles, il peut être intéressant de jeter un Error, mais ils sont rares.
zzzzBov
7
@zzzzBov Il n'y a rien de mal à lancer des erreurs pour le cas C, un crash ou une gravure. Je ne pense pas que vous devriez récupérer les erreurs et récupérer. Par exemple, document.getElementByIdne lance pas quand l'élément n'existe pas, il retourne simplement null. La même chose peut être faite pour presque tous les cas
Raynos
4
@ Raynos, lancer depuis une fonction de synchronisation est tout à fait acceptable et logique dans ce cas d'utilisation. Renvoyer une erreur à un rappel est asynchrone, une erreur de projection étant à synchroniser.
sbartell
@Raynos a-t-il un bon conseil pour éviter l'utilisation d'Erreurs / Exceptions pour le contrôle de flux côté client (environnement non-nœud)? J'ai trouvé ce billet sur StackOverflow , mais il est principalement destiné à Java
blong
@ b.long simple. ne jetez jamais d'erreurs. Problème résolu.
Raynos
32

Try / catch en Javascript n'est pas aussi sûr que dans d'autres langues, en raison de la nature asynchrone de Javascript. Considérez cet extrait:

try {
    setTimeout(function() {
        do_something_that_throws();
    }, 1000);
}
catch (e) {
    alert("You won't see this!");
}

Le problème est que le sort du flux de contrôle trybloc avant do_something_that_throws()est exécuté, de sorte que l'erreur renvoyée dans la fonction de rappel s'attrapée jamais.

Donc, essayer / attraper est fondamentalement inapproprié dans de nombreux cas, et il n'est pas toujours évident de savoir si quelque chose exécute le code de manière asynchrone ou non. Heureusement, javascript, avec son idiome particulier de rappel asynchrone à un seul thread et sa prise en charge des fermetures réelles, offre une alternative élégante: la gestion des erreurs de type continuation-pass. Il suffit de passer la bonne réponse à toute erreur en tant que fonction, par exemple:

setTimeout(function () {
    do_something_that_calls_err(function(err) {
        alert("Something went wrong, namely this: " + err);
    }),
    1000);
tdammers
la source
5
ce n'est pas la preuve de balle dans d'autres langues non plus. Portez ce code dans n’importe quelle langue prenant en charge les rappels asynchrones et il échouera également.
Raynos
2
@Raynos: Vous avez raison. cependant, d’autres langages (ou plutôt leurs cultures de support) n’achètent pas cela comme javascript au langage de rappel asynchrone, et en raison de la nature multithread de la plupart des autres environnements, les inconvénients de try / catch sont plus évidents et entouré de nombreuses autres mises en garde, de sorte que les personnes marchent naturellement avec prudence dans les situations de rappel multithreads / asynchrones et sont plus conscientes des pièges potentiels.
tdammers
Est-ce vraiment dû à la "nature asynchrone" de JavaScript? Autant que je sache, Try / Catch pourrait théoriquement être amené à fonctionner lexicalement de la même manière que les identifiants sont fermés lexicalement; ça ne se passe pas comme ça en JavaScript.
Brian Gordon
2
Dans node.js> = 0.8, il est à noter qu'il est possible d'essayer / de capturer de manière asynchrone, veuillez consulter ma question stackoverflow.com/questions/14301839/…
Benjamin Gruenbaum
La seule alternative au try-catch synchrone est-elle le style de passage de continuation asynchrone?
CMCDragonkai
23

Beaucoup de ces réponses sont un peu vieux et ne prennent pas en compte les nouvelles fonctionnalités de ES7 asyncet await.

En utilisant async/ awaitvous pouvez maintenant obtenir un flux de contrôle asynchrone comme vous le souhaitez:

async function email(address) {
  try {
    // Do something asynchronous that may throw...
    await sendEmail({ to: address, from: '[email protected]`, subject: 'Hello' })
  } catch(err) {
    if (err instanceof SomeCustomError) {
      elegantlyHandleError(err)
    } else {
      throw err
    } 
  }
})

En savoir plus sur async/ awaitici . Vous pouvez utiliser async/ awaitmaintenant en utilisant babel .

Dana Woodman
la source
Mais c'est semblable à un code synchrone
Atul Agrawal
@ AtulAgrawal oui, c'est le point. Async / wait vous permet d'écrire du code asynchrone dans un style synchrone, de sorte que vous puissiez éviter "l'appel au rappel" et l'enchaînement de nombreuses promesses. C'est une façon très agréable d'écrire du code asynchrone à mon avis
Dana Woodman
Alors, quel est l’avantage de l’utilisation de javascript si le code asynchrone est synchrone. parce que la plupart des gens utilisent javascript en raison de sa nature asynchrone
Atul Agrawal
2
@ AtulAgrawal vous obtenez le meilleur des deux mondes - vous appréciez la nature asynchrone du langage (car le code ci-dessus sera toujours exécuté de manière asynchrone - libérant le fil et tout le reste) et vous profiterez des avantages d'un style de codage plus convivial pour les programmeurs. Ce n'est pas sans problèmes, cependant ...
ZenMaster
15

try-catch en javascript est tout aussi valide et utile que dans tout autre langage qui les implémente. Il y a une raison majeure pour laquelle il n'est pas utilisé autant en javascript qu'en d'autres langues. C'est la même raison pour laquelle javascript est vu comme un langage de script très laid, c'est la même raison pour laquelle les gens pensent que les programmeurs javascript ne sont pas de vrais programmeurs:

  • Javascript est une langue incroyablement accessible et omniprésente

Le simple fait que tant de personnes soient exposées à javascript (en raison du seul langage pris en charge par les navigateurs) signifie que vous disposez de beaucoup de code non professionnel. Bien sûr, il y a aussi beaucoup de raisons mineures:

  • certaines choses en javascript sont asynchrones et ne catchpeuvent donc pas (trucs asynchrones)
  • il y a eu beaucoup de discussions exagérées sur la façon dont try-catch a un énorme impact sur les performances. Il a un peu frappé les performances , mais pour la plupart des codes, cela en vaut la peine.
  • (malheureusement) javascript a été implémenté d'une manière qui ignore souvent les erreurs en silence (modification automatique des chaînes en chiffres, par exemple)

Quoi qu'il en soit, try-catch devrait être utilisé, mais bien sûr, vous devriez apprendre à les utiliser correctement - comme tout le reste dans la programmation.

utilisateur250878
la source
3
Et pourquoi avez-vous déjà eu une voix par en dessous, oh une voix en bas?
user250878
D'accord. Je pense que la réponse acceptée est généralement vraie, mais il y a de bonnes raisons d'utiliser try-catch, et même de lancer, sauf lorsqu'il s'agit d'objets natifs. Lorsqu'une erreur est générée plutôt que transmise à un rappel, elle arrête l'exécution ultérieure et place la pile au premier bloc qui peut le gérer. Cela constitue un avantage considérable et convient parfaitement aux opérations synchrones, en particulier si elles impliquent une imbrication profonde. Il semble insensé de suggérer que les exceptions sont "mauvaises" (enfin, pour des raisons évidentes) - elles sont en réalité un outil très utile doté d'un "pouvoir" unique.
Point
2
Avez-vous déjà pris le temps de lire le code source de, disons, jQuery? Pratiquement aucune tentative d’interception n’est faite, sauf dans les cas mentionnés dans la réponse acceptée: détecter les fonctionnalités et utiliser des objets natifs / hôtes générant des erreurs. Pour appeler un code qui n'utilise pas beaucoup try-catch (comme jQuery), "non professionnel" semble idiot. Pour être honnête, je pense que ce sont surtout les nouveaux programmeurs Javascript, issus de Java, qui ont tendance à sur-utiliser les fonctionnalités du langage telles que try-catch.
Stijn de Witt
6

Je crois que la plupart des raisons qui try..catchsont rares en JavaScript sont dues au fait que le langage tolère assez bien les erreurs. La grande majorité des situations peuvent être gérées à l'aide de vérifications de code, de valeurs par défaut correctes et d'événements asynchrones. Dans certains cas, le simple fait d'utiliser un modèle évite les problèmes:

function Foo() {
    //this may or may not be called as a constructor!!
    //could accidentally overwrite properties on window
}

function Bar() {
    if (!(this instanceof Bar)) {
        return new Bar();
    }
    //this will only work on Bar objects, and wont impact window
}

Certains des problèmes majeurs dans d'autres langues qui provoquent des exceptions n'existent tout simplement pas dans JS. Le typage n'est pas nécessaire la grande majorité du temps. Au lieu de cela, la méthode préférée consiste généralement à vérifier les fonctionnalités (application d'une interface particulière):

function doFoo(arg) {
    if (arg.foo) {
        arg.foo();
    } else {
        Bar.prototype.foo.call(arg);
    }
}

Avec l'ajout de async/ awaità la langue, try..catchdevient plus répandu. Les promesses étant la forme asynchrone de try..catch, il est logique d'attendre:

doSomething().then(
  doSomethingWithResult,
  doSomethingWithError
)

à la place être écrit comme:

try {
  const result = await doSomething()
  doSomethingWithResult(result)
} catch (e) {
  doSomethingWithError(e)
}
zzzzBov
la source
3

Peut-être une autre raison pour laquelle try / catch n'est pas très utilisé en Javascript est que la construction n'était pas disponible dans les toutes premières versions de Javascript ... elle a été ajoutée plus tard.

En conséquence, certains navigateurs plus anciens ne le prennent pas en charge. (En fait, cela pourrait provoquer une erreur d'analyse syntaxique / syntaxique dans certains navigateurs plus anciens, ce qui est plus difficile à "programmer de manière défensive" que la plupart des autres types d'erreur.)

Plus important encore, comme il n'était pas disponible initialement, les fonctions intégrées à Javascript qui ont été initialement publiées (ce que l'on appellerait les fonctions "de bibliothèque" dans de nombreuses langues) ne l'utilisent pas. (Cela ne marche pas très bien pour "attraper" une erreur de someobject.somefunction () si elle ne "jette" pas, mais retourne simplement "null" quand elle rencontre un problème.)


Une autre raison possible est que le mécanisme try / catch ne semblait pas nécessaire au départ (et ne semble toujours pas si utile). Ce n'est vraiment nécessaire que lorsque les appels sont régulièrement imbriqués sur plusieurs niveaux; renvoyer une sorte d'ERRNO fonctionnerait très bien pour les appels directs (bien que pour le rendre vraiment utile chaque fois qu'il est disponible, la meilleure pratique dans la plupart des langues consiste à l'utiliser partout plutôt que sur des appels profondément imbriqués). Comme la logique Javascript devait à l'origine être petite et simple (après tout, c'est simplement un ajout à une page Web :-), les appels de fonction ne devaient pas être profondément imbriqués, et un mécanisme try / catch ne semblait donc pas nécessaire.

Chuck Kollars
la source
3
Non non non, absolument pas le cas. Les moteurs vieux ne comptent plus depuis très longtemps et la communauté javascript en général est rapide à abandonner les choses anciennes lorsque cela est justifié. Je parierais même que la majorité des développeurs javascript sont désormais post-IE6.
Camilo Martin
0

Je pense qu'elles ne sont pas très utilisées car le fait de jeter des exceptions dans le code Javascript du côté client rend plus difficile le débogage d'une page.

Plutôt que de jeter des exceptions, je préfère généralement montrer zone d'alerte al, (c. -à alert("Error, invalid...");)

Cela peut sembler étrange, mais des erreurs javascript se produisent côté client. Si un client utilise une page que vous avez créée et que la page génère une exception, à moins que le client ne soit un informaticien averti des technologies, il ne pourra jamais le savoir. vous quel est le problème.

Il vous appellera seulement en vous disant: "Hé, la page X ne marche pas!", Et ce sera à vous de trouver ce qui ne va pas et où se trouve le code.

En utilisant la boîte d'alerte, il est plus probable qu'il appelle et dise quelque chose du genre: "Hé, quand je clique sur le bouton A de la page X, il affiche une boîte qui dit ..." , croyez-moi, ce sera beaucoup plus facile à trouver. l'insecte.

Marco Demaio
la source