try-catch em javascript… não é uma boa prática?


69

Existe uma provisão para o bloco try-catch em javascript . Enquanto em java ou em qualquer outro idioma é obrigatório ter tratamento de erros, não vejo ninguém usando-os em javascript para maior extensão. Não é uma boa prática ou simplesmente não precisamos deles em javascript?


2
While in java or *any other language* it is mandatory to have error handling...- Na verdade não. Java, sim, mas há muitas linguagens que não insistem em tentar pegar (como C #).
Jim G.

Isso ocorre porque você não pode usá-los em um ambiente assíncrono. Eu usá-los muitas vezes por código de sincronização por um nível de abstração mais baixo, por exemplo, transformando algo em algo, etc ...
inf3rno

Aposto que você vê mais códigos try-catch no lado do servidor do que no lado do cliente. A maior parte do código do lado do cliente que você conhece não faz nada de importante. Eu apostaria que minimizar a KB no canal é mais importante do que recuperar todos os erros - na maioria dos aplicativos e nas circunstâncias do navegador.
precisa saber é

Existe uma outra maneira de evitar tentar capturar usando talvez e Ou (mônadas), tínhamos um raspador de Web escrito no nó. Conseguimos remover todas as tentativas de captura usando-o.
precisa saber é

Respostas:


66

Deve-se evitar throwerros como a maneira de transmitir condições de erro nos aplicativos.

A throwdeclaração deve ser usada apenas "Para que isso nunca aconteça, bata e queime. Não se recupere de forma elegante"

try catch no entanto, é usado em situações em que objetos host ou ECMAScript podem gerar erros.

Exemplo:

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

As recomendações na comunidade node.js são que você transmite erros nos retornos de chamada (porque os erros ocorrem apenas para operações assíncronas) como o primeiro argumento

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
})

Também há outros problemas, como o try / catch é muito caro e é feio e simplesmente não funciona com operações assíncronas.

Portanto, como as operações síncronas não devem gerar um erro e não funcionam com operações assíncronas, ninguém usa try catch, exceto os erros gerados pelos objetos host ou pelo ECMAScript


2
Eu não chegaria ao ponto de dizer que ninguém usa try catch, é apenas a ferramenta errada para o trabalho na maioria dos casos. Quando há circunstâncias verdadeiramente excepcionais, pode valer a pena dar uma Error, mas são poucas e distantes entre si.
ZzzzBov 13/04/12

7
@zzzzBov Não há nada errado em lançar erros para o caso C, travar e gravar. Só acho que você não deve pegar erros e se recuperar. Por exemplo document.getElementById, não lança quando o elemento não existe, apenas retorna null. O mesmo pode feito por quase todos os casos
Raynos

4
@ Raynos, jogar a partir de uma função de sincronização é totalmente aceitável e faz sentido nesse caso de uso. Retornar erro ao retorno de chamada é assíncrono, assim como o erro de lançamento é sincronizado.
sbartell

@Raynos tem algum bom conselho sobre como evitar erros / exceções para controle de fluxo no lado do cliente (ambiente que não é do nó)? Eu encontrei este post no StackOverflow , mas ele é voltado principalmente para Java #
18413

@ muito simples. nunca jogue erros. Problema resolvido.
Raynos

32

A tentativa / captura no Javascript não é tão à prova de balas quanto em outros idiomas, devido à natureza assíncrona do Javascript. Considere este trecho:

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

O problema é que o fluxo de controle sai do trybloco antes de do_something_that_throws()ser executado, para que o erro gerado dentro do retorno de chamada nunca seja detectado.

Portanto, try / catch é basicamente inadequado em muitos casos, e nem sempre é óbvio se algo executa código de forma assíncrona ou não. Felizmente, o javascript com seu idioma peculiar de retorno de chamada assíncrono com thread único e seu suporte para fechamentos reais fornece uma alternativa elegante: tratamento de erros no estilo de passagem de continuação. Basta passar a resposta adequada a qualquer erro como uma função, por exemplo:

setTimeout(function () {
    do_something_that_calls_err(function(err) {
        alert("Something went wrong, namely this: " + err);
    }),
    1000);

5
também não é à prova de balas em outros idiomas. Portar esse código para qualquer idioma que suporte retornos de chamada assíncronos e também falhará.
Raynos

2
@ Raynos: Você está certo; no entanto, outros idiomas (ou melhor, suas culturas de suporte) não compram muito isso no idioma de retorno de chamada assíncrona como o Javascript, e devido à natureza multithread da maioria dos outros ambientes, as deficiências de try / catch são mais óbvias e cercado por muitas outras advertências, as pessoas naturalmente andam com cuidado em situações de retorno de chamada multithread / assíncronas e estão mais conscientes das possíveis armadilhas.
tdammers

Isso é realmente devido à "natureza assíncrona do JavaScript?" Tanto quanto eu posso ver, o Try / Catch poderia, teoricamente, ser feito para funcionar lexicamente, como o modo como os identificadores são lexicamente fechados; simplesmente não funciona dessa maneira em JavaScript.
Brian Gordon

2
No node.js> = 0.8, vale a pena notar que é possível tentar / capturar de forma assíncrona, por favor, veja minha pergunta stackoverflow.com/questions/14301839/…
Benjamin Gruenbaum

A única alternativa ao try-catch síncrono é o estilo de passagem de continuação assíncrona?
precisa saber é o seguinte

23

Muitas dessas respostas são um pouco antigas e não levam em conta os novos recursos asynce do ES7 await.

Usando async/ awaitagora você pode obter um fluxo de controle assíncrono como desejar:

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

Saiba mais sobre async/ awaitaqui . Você pode usar async/ awaitagora usando babel .


Mas é semelhante a um código síncrono
Atul Agrawal

@AtulAgrawal sim, esse é o ponto. Async / waitit permite escrever código assíncrono em um estilo síncrono para evitar o "inferno de retorno de chamada" e encadear muitas promessas. É uma maneira muito agradável de escrever código assíncrono na minha opinião
Dana Woodman

então qual é a vantagem de usar o javascript se estivermos transformando o código assíncrono em síncrono? porque a maioria das pessoas usam javascript devido à sua natureza assíncrona
Atul Agrawal

2
@AtulAgrawal, você obtém o melhor dos dois mundos - desfruta da natureza assíncrona da linguagem (como o código acima ainda será executado assíncrono - liberando o encadeamento e tudo) e obtém os benefícios de um estilo de codificação mais amigável para programadores. Não é sem problemas, embora ...
Zenmaster

15

try-catch em javascript é tão válido e útil quanto em qualquer outro idioma que os implemente. Há um motivo principal para não ser usado tanto em javascript quanto em outros idiomas. É o mesmo motivo pelo qual o javascript é visto como uma linguagem de script feia, o mesmo motivo pelo qual as pessoas pensam que os programadores de javascript não são programadores de verdade:

  • Javascript é uma linguagem incrivelmente acessível e difundida

O simples fato de tantas pessoas serem expostas ao javascript (em virtude do único idioma suportado pelos navegadores) significa que você tem muitos códigos não profissionais por aí. Claro que também existem muitos motivos menores:

  • algumas coisas no javascript são assíncronas e, portanto, não são catchcapazes (coisas assíncronas)
  • houve muita conversa exagerada sobre como o try-catch tem um enorme impacto no desempenho. Tem um pouco de impacto no desempenho , mas para a maioria dos códigos vale a pena.
  • O javascript foi (infelizmente) implementado de uma maneira que geralmente ignora silenciosamente os erros (alterando automaticamente as strings para números, por exemplo)

Independentemente disso, o try-catch deve ser usado, mas é claro que você deve aprender como usá-los adequadamente - como tudo na programação.


3
E por que você já recusou votos, oh voto silencioso?
User250878 24/04

Acordado. Acho que a resposta aceita geralmente é verdadeira, mas há boas razões para usar o try-catch e até mesmo jogar, além de lidar com objetos nativos. Quando um erro é lançado em vez de passado para um retorno de chamada, ele interrompe a execução e salta a pilha para o primeiro bloco que pode lidar com isso. Essa é uma grande vantagem e faz todo sentido para operações síncronas, especialmente se elas envolverem aninhamento profundo. Parece loucura sugerir que as exceções são "ruins" (bem, exceto pelas razões óbvias) - elas são na verdade uma ferramenta muito útil com um "poder" único.
Ponto-

2
Você já leu o código fonte do, digamos, jQuery? Quase nenhuma tentativa de captura, exceto exatamente os cenários mencionados na resposta aceita: detectar recursos e usar objetos nativos / host que geram erros. Chamar código que não usa muito o try-catch (como o jQuery) 'não profissional' parece bobagem. Para ser sincero, acho que são especialmente os novos programadores Javascript vindos de Java que tendem a usar recursos de linguagem como o try-catch.
Stijn de Witt

6

Acredito que muito do motivo try..catchraro no JavaScript seja porque a linguagem tem uma tolerância bastante alta a erros. A grande maioria das situações pode ser tratada usando verificações de código, bons padrões e eventos assíncronos. Em alguns casos, o simples uso de um padrão evitará problemas:

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
}

Alguns dos principais problemas em outros idiomas que causam exceções simplesmente não existem no JS. A conversão de tipos não é necessária na grande maioria das vezes. Em vez disso, o método preferido é tipicamente apresentar a verificação (aplicando uma interface específica):

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

Com a adição de async/ awaitpara o idioma, try..catchestá se tornando mais prevalente. Promete ser a forma assíncrona de try..catch, faz sentido que se deva esperar:

doSomething().then(
  doSomethingWithResult,
  doSomethingWithError
)

para ser escrito como:

try {
  const result = await doSomething()
  doSomethingWithResult(result)
} catch (e) {
  doSomethingWithError(e)
}

3

Possivelmente, outro motivo pelo qual o try / catch não é muito usado no Javascript é que o construto não estava disponível nas primeiras versões do Javascript ... foi adicionado mais tarde.

Como resultado, alguns navegadores mais antigos não são compatíveis. (Na verdade, isso pode causar um erro de analisador / sintaxe em alguns navegadores antigos, algo mais difícil de "programar defensivamente" do que a maioria dos outros tipos de erros.)

Mais importante, como não estava disponível inicialmente, as funções internas do Javascript que foram lançadas inicialmente (o que se chamaria de funções de "biblioteca" em muitos idiomas) não a utilizam. (Ele não funciona muito bem para "capturar" um erro de someobject.somefunction () se não "dispara", mas apenas retorna "nulo" quando encontra um problema.)


Outro motivo possível é que o mecanismo try / catch não parecia necessário inicialmente (e ainda não parece tão útil). É realmente necessário apenas quando as chamadas são aninhadas rotineiramente em vários níveis; apenas devolver algum tipo de ERRNO funcionaria bem para chamadas diretas (embora para torná-lo realmente útil sempre que disponível, a melhor prática na maioria dos idiomas é usá-lo em qualquer lugar, em vez de apenas em chamadas profundamente aninhadas). Como originalmente se esperava que a lógica Javascript fosse pequena e simples (afinal, é apenas um complemento de uma página da web :-), não se esperava que as chamadas de função estivessem profundamente aninhadas e, portanto, um mecanismo de tentativa / captura não parecia necessário.


3
Não, não, não, absolutamente não é o caso. Motores antigos não importam mais por muito tempo e a comunidade javascript em geral rapidamente deixa de lado os itens antigos quando justificado. Eu até apostaria que a maioria dos desenvolvedores de javascript agora é pós-IE6.
Camilo Martin

0

Acredito que eles não são muito utilizados, porque lançar exceções no código do lado do cliente Javascript torna mais difícil a depuração de uma página.

Em vez de lançar exceções, geralmente prefiro mostrar todas as caixas de alerta (ou seja alert("Error, invalid...");)

Pode parecer estranho, mas erros de Javascript acontecem no lado do cliente, se um cliente estiver usando uma página que você construiu e a página lança uma exceção, a menos que o cliente seja um codificador experiente em tecnologia, não há como ele saber você qual é o problema.

Ele só ligará para você dizendo: "Ei, a página X não funciona!", E então tudo depende de você descobrir o que deu errado e onde está no código.

Ao usar a caixa de alerta, é mais provável que ele ligue e diga algo como: "Ei, quando clico no botão A da página X, ele mostra uma caixa que diz ..." , confie em mim, será muito mais fácil encontrar O inseto.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.