aguarde...

27 de maio de 2020

Tratamento de erros em JavaScript

Tratamento de erros em JavaScript

Saber como gerenciar erros é parte importante da programação. Este tutorial fornece uma introdução fácil ao tratamento de erros em JavaScript. Você aprenderá sobre dois tipos de erros e como lidar com cada um. Você também aprenderá como usar try...catchthrowinstruções para tornar seu código mais seguro e muito mais.

Dois tipos principais de erros

Quando se trata de manipulação de erros no JavaScript, existem dois tipos de erros que você pode encontrar. O primeiro tipo de erros são erros de sintaxe. O segundo tipo são erros de tempo de execução.

Erros de sintaxe

Erros de sintaxe também são chamados de erros de análise. Isso ocorre quando o analisador JavaScript interpreta seu código. Quando um desses erros ocorre, afeta apenas o código que está no mesmo encadeamento. O restante do código não é afetado. Um exemplo de erro de sintaxe pode ser esquecido ao abrir ou fechar parênteses ou colchete.

Outro exemplo pode estar faltando coma ou dois pontos no objeto. Qualquer um desses erros fará com que a sintaxe seja inválida e interrompa seu programa. Existem algumas maneiras de evitar esses tipos de erros. Um é verificar o seu código e procurá-los. Isso não é eficaz e pode levar muito tempo.

Outra opção é usar alguma ferramenta ou plugin IDE. Essas ferramentas verificarão automaticamente seu código e procurarão por problemas de sintaxe. As três ferramentas mais populares que ajudarão a detectar erros de sintaxe são eslint , jshint e jslint . Eslint é o meu favorito. Eu uso em quase todos os meus projetos.

Essas ferramentas são muito populares e os desenvolvedores não gostam de tarefas repetitivas. Isso torna provável a existência de um plug-in para cada uma dessas ferramentas que você pode instalar no IDE que está usando. Se você encontrar alguns, eu recomendo instalá-lo e usá-lo. Pode poupar muitas dores de cabeça.

Erros de tempo de execução

O segundo tipo de erros são erros de tempo de execução. Esses erros também são chamados de exceções. Esses erros ocorrem durante a execução do seu código, quando você o executa. Um exemplo simples pode ser chamar um método que não existe. Outra pode estar passando a string para uma função em vez do número ou o contrário.

Importante é que cada um desses erros seja válido na visualização do JavaScript. Sim, você pode digitar incorretamente algum nome de variável ou função. No entanto, a própria sintaxe ainda é válida. Não faltam dois pontos ou colchetes. Se isso for verdade, o JavaScript permitirá que seu código seja compilado. Você encontra esses erros apenas quando executa seu código.

É também isso que torna os erros de tempo de execução mais difíceis de lidar. É também por isso que é uma boa idéia escrever e também executar testes de unidade . Além disso, não há plug-in que o ajude a identificar esses erros antes que eles ocorram. Bem, isso é verdade apenas parcialmente. Você pode usar um superconjunto de JavaScript, como o TypeScript .

Se o seu IDE tiver suporte para um desses superconjuntos, ele ajudará a detectar erros de tempo de execução. Por exemplo, quando você usa o TypeScript no código VS, ele avisa quando alguma função ou variável que você deseja usar está indefinida. Também sugerirá métodos e variáveis ​​que você definiu anteriormente enquanto escreve seu código.

Além disso, existem algumas ferramentas internas do JavaScript que facilitarão o tratamento de erros. Vamos dar uma olhada nessas ferramentas.

Tratamento de erros e tentativa… catch

A primeira ferramenta para tratamento de erros é uma try...catchdeclaração. Esta declaração pode ser semelhante à if...elsedeclaração. Ele também contém dois blocos de código, embrulhados com chaves. No entanto, não há parênteses antes do primeiro bloco, o trybloco. Este trybloco contém o código que você deseja tentar executar.

try {
  // some code
}

Dito isto, todo o seu código não precisa ser definido em um único trybloco gigante . Em vez disso, você coloca no trybloco apenas o que deseja executar. Por exemplo, digamos que você queira declarar alguma função . Você pode declarar essa função em algum lugar fora do trybloco, mas invoca a função dentro dele.

// Declare function outside try block
function myFunction() {
  // do something
}

// Create try block
try {
  // And invoke the function inside it
  myFunction()
}

Pegar

Quando você fizer isso, o trybloco chamará essa função. Se sua função for executada sem erros, nada acontecerá. Se houver alguns erros de tempo de execução? É aqui que o catchbloco entra em jogo. O catchbloco é semelhante a try. Uma diferença é que existem parênteses após a catchpalavra – chave e antes de abrir a chave.

Dentro desses parênteses está definido um parâmetro. Este parâmetro é um objeto de erro. Este objeto contém informações sobre o erro que ocorreu. Ele contém o nome do erro, a mensagem de erro e a pilha de chamadas atual. O catchbloco é um local onde você define o que fazer quando ocorrer um erro.

// Create try...catch statement
try {
  // Run some code
}
catch(error) { // error is the error object, you can use a different name
  // Do something when an error occurs
}


// Example:
// Create try...catch statement
try {
  // Try to invoke function that doesn't exist
  myFunc()
}
catch(error) {
  console.log('Error name: ', error.name)
  console.log('Error message: ', error.message)
  console.log('Error stack: ', error.stack)
  console.log('Error: ', error)
}

// Outputs:
// 'Error name: ' 'ReferenceError'

// 'Error message: ' 'myFunction is not defined'

// 'Error stack: ' `ReferenceError: myFunction is not defined
//     at eval (eval at <anonymous> (:7:47), <anonymous>:4:3)
//     at <anonymous>:7:47
//     at <anonymous>:15:9`
//     ...

// 'Error: ' ReferenceError: myFunction is not defined
    // at eval (eval at <anonymous> (:7:47), <anonymous>:4:3)
    // at <anonymous>:7:47
    // at <anonymous>:16:9
    //     ...

O parêntese e o objeto de erro após a catchpalavra – chave e antes de abrir o colchete são opcionais. É usado para passar as informações sobre erro. Se você não quiser usar essas informações, poderá omitir os dois, o parêntese e o objeto de erro. A try...catchdeclaração ainda funcionará.

// Create try...catch statement
try {
  // Try to invoke function that doesn't exist
  myFunction()
}
catch { // Omit parenthesis and error object
  // Show some custom error message
  console.log('An error occurred.')
}

// Outputs:
// 'An error occurred.'

Experimente, pegue e controle

O código dentro do catchbloco é executado imediatamente quando ocorre algum erro de tempo de execução. Isso é importante, lembre-se. Se algum código que você executar no trybloco levar a um erro, qualquer código a seguir, dentro do mesmo trybloco, não será executado. O catchbloco assumirá automaticamente o controle e processará o erro.

// Create function that leads to an error
function myFuncWithError() {
  throw 'Error'
}

// Create another function that doesn't lead to an error
function myFunc() {
  console.log('Hello.')
}

// Create try...catch statement
try {
  // Invoke the myFuncWithError function
  // If this function causes error...
  myFuncWithError()

  // Invoke the myFunc function
  // ...this function will never be invoked
  myFunc()
}
catch(error) {
  // Log any error message
  console.log(error)
}

// Outputs:
// 'Error'

// Note:
// Only myFuncWithError() function was invoked
// then control shifted to catch block
// and myFunc() function was never invoked

Usando várias instruções try… catch

Existe uma maneira de corrigir isso. Em JavaScript, não há limite para quantas try...catchinstruções você pode usar. Também não há uma regra que você precise usar uma para todo o seu código. Se alguma coisa, você deve realmente fazer o oposto. O uso de várias try...catchinstruções permite isolar erros e não afetar o restante do seu código.

Se você deseja chamar as duas funções, a coisa mais fácil que você pode fazer é criar duas try...catchinstruções. Em seguida, você pode invocar uma função na primeira instrução e outra função na segunda.

// Create function that leads to an error
function myFuncWithError() {
  throw 'Error'
}

// Create another function that doesn't lead to an error
function myFunc() {
  console.log('Hello.')
}

// Create first try...catch statement
try {
  // Invoke the myFuncWithError function
  myFuncWithError()
}
catch(error) {
  // Log any error message
  console.log(error)
}

// Create second try...catch statement
try {
  // Invoke the myFunc function
  myFunc()
}
catch(error) {
  // Log any error message
  console.log(error)
}

// Outputs:
// 'Error'
// 'Hello.'

// Note: both functions were successfully invoked
// because error that occurred in the first
// was caught by the first try...catch statement
// and had no effect on the second function

O exemplo funcionaria com qualquer número de função ou código que você deseja chamar ou executar. Você pode criar dezenas ou mais try...catchinstruções para lidar com um caso de uso específico. Portanto, qualquer erro que ocorra não afetará o restante do seu código, invocado ou executado em outras try...catchinstruções.

Como você pode ver, a try...catchdeclaração é uma ferramenta muito poderosa para o tratamento de erros. Ele permite que você execute partes do seu código sem deixá-lo travar em outras partes ou em todo o aplicativo. Dito isto, há mais.

Finalmente

try...catchdeclaração pode ajudá-lo a facilitar o tratamento de erros. No entanto, também há um finallybloco que você pode usar. O trychama o código dentro do bloco. O catché chamado quando ocorre um erro. O finallyé invocado no final de cada try...catch...finallyinstrução.

O importante é que o finallyé invocado em todos os casos. Não importa se há um erro ou não. O finallyserá invocado. Isso pode ser útil quando você faz algo no final de cada bloco. A sintaxe de finallyé a mesma que para try.

Existe a finallypalavra – chave seguida pelo bloco de código para executar envolto em chaves. Não há parênteses, mesmo opcional.

// Create try...catch...finally statement
try {
  // Run some code
}
catch(err) {
  // Log any error message
  console.log(err)
}
finally {
  // Do something whether is an error or not
}


// Example:
try {
  // Try to invoke non-existing function
  myFunc()
}
catch(err) {
  // Log any error message
  console.log(err.message)
}
finally {
  // Log a message at the end of execution of the try...catch...finally statement
  console.log('The end of try...catch...finally statement.')
}

// Outputs:
// 'myFunc is not defined'
// 'The end of try...catch...finally statement.'

Captura um tanto opcional

Até agora, sempre cometíamos erros ao usar todos os blocos try...catchou try...catch...finallyinstruções. Uma coisa que você deve saber é que o catché, da mesma forma que o finally, também é opcional. Dito isto, isso não significa que é uma boa idéia omitir isso.

Quando você omite o catchbloco, qualquer erro que ocorra durante a execução do trybloco “vazará” para fora. Sem o catchbloco, não há nada que capte algum erro e o processe. Então, você pode omiti-lo? Sim. Você pode usar apenas tryou try...finally. Ambos, vai funcionar. No entanto, nenhum erro será detectado.

// Create try statement
try {
  myFunc()
}


// Create try...finally statement
try {
  myFunc()
}
finally {
  console.log('try...finally is finished.')
}

Tente… pegar a instrução dentro das funções

Todo o tratamento de erros anterior mostra cantar try...catchem um escopo global, fora de quaisquer funções. Isso não significa que a try...catchdeclaração esteja restrita ao escopo global. Não é. Você pode usar em um escopo global ou local, criado por uma função, por exemplo. Isso também funcionará.

// Declare new function that takes one parameter
function myFunction(name) {
  // Add try...catch statement
  try {
    // If value passed as name parameter is not a string
    if (typeof name !== 'string') {
      // Throw a TypeError
      throw new TypeError('The name value of parameter must be a string!')
    } else {
      console.log(`Hello ${name}.`)
    }
  }
  catch(err) {
    // Log
    console.log(err)
  }
}

myFunction(11)
// Outputs:
// TypeError: The name value of parameter must be a string!
//     at myFunction (eval at <anonymous> (:7:47), <anonymous>:6:13)
//     at eval (eval at <anonymous> (:7:47), <anonymous>:13:1)
//     at <anonymous>:7:47
//     at <anonymous>:19:23
//     ...

myFunction('Jack')
// Outputs:
// 'Hello Jack.'

Criando e lançando erros

Para tratamento de erros, você pode usar erros JavaScript integrados ou pode definir seus próprios. Nas duas abordagens, você usará a throwinstrução Esta declaração especifica o valor que você deseja lançar como um erro. Você já usou esta declaração no exemplo na seção “Experimente, captura e controle”, dentro do declaration myFuncWithError() function.

Criando erros simples

Vamos dar uma olhada na primeira maneira de criar um erro personalizado. Este será um erro muito simples. Você fará isso usando uma throwinstrução com uma string, número ou qualquer outro tipo de dados . Por exemplo, vamos criar uma função simples que, quando você a chama, gera um erro personalizado. Este erro personalizado será uma sequência.

// Create function
function myFunc() {
  // Throw a custom error
  throw 'My custom error.'
}

// Create try...catch statement
try {
  // Invoke the myFunc() function
  myFunc()
}
catch(err) {
  // Log the error
  console.log('Error: ', err)
  console.log('Error name: ', err.name)
  console.log('Error message: ', err.message)
  console.log('Error stack: ', err.stack)
}

// Outputs:
// 'Error: ' 'My custom error.'
// 'Error name: ' undefined
// 'Error message: ' undefined
// 'Error stack: ' undefined

Como você pode ver, é fácil criar um erro simples. A desvantagem de criar erros desta maneira é que esses erros personalizados não terá namemessagestackpropriedades. Existe uma maneira de corrigir isso. Uma maneira simples de fazer isso é usar um objeto em vez de um tipo de dados primitivo.

Então, em vez de jogar uma string ou outra primitiva, você jogará um objeto. Dentro deste objeto, você definirá todas as propriedades que normalmente existiriam em um objeto de erro, the namemessagestack. Agora, quando esse erro personalizado ocorre, você também pode acessar seus namemessagestack.

// Create function
function myFunc() {
  // Throw a custom error object
  throw {
    name: 'MyCustomError',
    message: 'An error occurred.',
    stack: 'myFunc()'
  }
}

try {
  // Invoke the myFunc() function
  myFunc()
}
catch(err) {
  // Log the error
  console.log('Error: ', err)
  console.log('Error name: ', err.name)
  console.log('Error message: ', err.message)
  console.log('Error stack: ', err.stack)
}

// Outputs:
// 'Error: ' {
//   name: 'MyCustomError',
//   message: 'An error occurred.',
//   stack: 'myFunc()'
// }
// 'Error name: ' 'MyCustomError'
// 'Error message: ' 'An error occurred.'
// 'Error stack: ' 'myFunc()'

Criando erros com construtores de erro internos do JavaScript

Outra opção para a criação de novos erros é usando JavaScript embutido construtores de erro, como ErrorTypeErrorReferenceErrorSyntaxErrorRangeErrorEvalErrorInternalErrorURIError. Você usará a throwinstrução para gerar esses erros personalizados também. Você também precisará usar a palavra-chave newjunto com um dos nomes do construtor.

newpalavra-chave diz que você está criando uma nova instância de um construtor. Nesse caso, algum construtor de erros. Quando você usa um desses construtores, a namepropriedade dentro do errorobjeto será o construtor que você usou. O messageserá a seqüência que você passar como um argumento quando você instancia o construtor.

// Create function
function myFunc() {
  // Throw a custom error using Error constructor
  // The Error will be the "name" property in error object
  // The 'An error occurred.' will be the "message" property in error object
  throw new Error('An error occurred.')
}

try {
  myFunc()
}
catch(err) {
  console.log('Error: ', err)
  console.log('Error name: ', err.name)
  console.log('Error message: ', err.message)
  console.log('Error stack: ', err.stack)
}

// Outputs:
// 'Error: ' Error: An error occurred.
//     at myFunc (eval at <anonymous> (:7:47), <anonymous>:4:9)
//     at eval (eval at <anonymous> (:7:47), <anonymous>:8:3)
//     at <anonymous>:7:47
//     at <anonymous>:20:9
//     ...

// 'Error name: ' 'Error'

// 'Error message: ' 'An error occurred.'

// 'Error stack: ' `Error: An error occurred.
//     at myFunc (eval at <anonymous> (:7:47), <anonymous>:4:9)
//     at eval (eval at <anonymous> (:7:47), <anonymous>:8:3)
//     at <anonymous>:7:47

Criando erros personalizados com o construtor Function e a classe

Juntamente com os construtores de erro internos do JavaScript, você também pode criar erros personalizados com o construtor ou a classe Function . Aqui está como. Você precisa usar o construtor de funções para criar um novo erro personalizado. Este construtor de função terá um parâmetro quando você o usar. Esta será a mensagem de erro.

Dentro deste construtor, você irá adicionar três propriedades, namemessagestack. A namepropriedade conterá o nome do seu erro personalizado. O messageirá se referir ao valor passado como messageparâmetro. O stackusarástack propriedade do Errorconstrutor instanciado recentemente .

Quando você tem isso, é necessário definir a prototypepropriedade desse novo construtor Function como construtor de erros. Por fim, você também deve definir a constructorpropriedade do construtor Function em prototypeproperty para o construtor Function. Quando você tem isso, usa thrownewinstruções para criar novos erros com base no seu construtor de erros customizado.

// Create new custom error using Function constructor
const MyCustomError = function(message) {
  // Add name property with some custom name
  this.name = 'MyCustomError'
  // Add message property referencing the value passed as "message" parameter
  this.message = message
  // Add stack property from Error constructor
  this.stack = (new Error()).stack
}

// Set "prototype" property of custom error constructor to Error constructor
MyCustomError.prototype = new Error()

// Set the "constructor" property of custom error constructor to the custom error constructor
MyCustomError.prototype.constructor = MyCustomError


// Usage:
// Create function
function myFunc() {
  // Use custom error constructor to create new error
  throw new MyCustomError('An error occurred.')
}

// Create try...catch statement
try {
  // Invoke function with custom error
  myFunc()
}
catch(err) {
  // Log error data
  console.log('Error: ', err)
  console.log('Error name: ', err.name)
  console.log('Error message: ', err.message)
  console.log('Error stack: ', err.stack)
}

// Outputs:
// 'Error: ' Error
//     at new MyCustomError (eval at <anonymous> (:7:47), <anonymous>:6:16)
//     at myFunc (eval at <anonymous> (:7:47), <anonymous>:13:9)
//     at eval (eval at <anonymous> (:7:47), <anonymous>:17:3)
//     at <anonymous>:7:47
//     at <anonymous>:26:9
//     ...

// 'Error name: ' 'MyCustomError'

// 'Error message: ' 'An error occurred.'

// 'Error stack: ' `Error
//     at new MyCustomError (eval at <anonymous> (:7:47), <anonymous>:6:16)
//     at myFunc (eval at <anonymous> (:7:47), <anonymous>:13:9)
//     at eval (eval at <anonymous> (:7:47), <anonymous>:17:3)
//     at <anonymous>:7:47
//     at <anonymous>:28:9
//     ...

Com a classe JavaScript, criar um construtor de erros personalizado é ainda mais fácil. Primeiro, você deve criar uma nova classe para o construtor de erros personalizado. Esta classe será extendaError classe. Dentro da classe, você adicionará constructorcom um parâmetro. Esta será a mensagem de erro.

Dentro do constructor, você tem que chamar supercom messagepassado como argumento. Isso chamará o construtor da classe pai Error. Depois disso, ainda dentro do constructor, você substituirá a namepropriedade adicionando sua própria namepropriedade com o nome do seu construtor personalizado.

// Create new error constructor with JavaScript class
class MyCustomError extends Error {
  constructor(message) {
    // Call constructor of parent class Error
    super(message)

    // Set your custom error name
    this.name = 'MyCustomError'
  }
}

// Create try...catch statement
try {
  // Throw new custom error
  throw new MyCustomError('An error occurred')
}
catch(err) {
  console.log('Error name: ', err.name)
  console.log('Error message: ', err.message)
  console.log('Error stack: ', err.stack)
}

// Outputs:
// 'Error name: ' 'MyCustomError'

// 'Error message: ' 'An error occurred'

// 'Error stack: ' `MyCustomError: An error occurred
//     at eval (eval at <anonymous> (:7:47), <anonymous>:12:9)
//     at <anonymous>:7:47
//     at <anonymous>:23:9
//     ...

Erro ao manipular globalmente

try...catchetry...catch...finally declarações são poderosas. Esses dois podem facilitar o tratamento de erros. Um problema pode ser se você não conseguir isolar o código que deseja executar com o trybloco. Por exemplo, quando algum código é executado em um escopo global a partir de um local onde você não pode acessá-lo.

Nesse caso, você pode usar o onerror()método Este é um manipulador de eventos de erro. Você pode usá-lo para capturar e processar erros que ocorrem em um escopo global. Além do windowobjeto, você também pode usá-lo com elementos no DOM. Como alternativa, você pode anexar um novo ouvinte de errorevento para evento, em um windowou em algum elemento.

// Option no.1: onerror() method
window.onerror = function(message, url, lineNumber, columnNumber, error) {
  console.log(`
    error message: ${message},
    error URL: ${url},
    line with error: ${lineNumber},
    column with error: ${columnNumber}
  `)
}


// Option no.2: listening to 'error' event
window.addEventListener('error', function(event) {
  console.log(`
    error message: ${event.message},
    error URL: ${event.filename},
    line with error: ${event.lineno},
    column with error: ${event.colno},
    error object: ${JSON.stringify(event.error)}
  `)
})

Conclusão: Tratamento de erros em JavaScript

Parabéns! Você acabou de concluir este tutorial sobre tratamento de erros em JavaScript. Espero que tenha gostado. Se você me acompanhou, deve ter uma boa idéia sobre como lidar com erros no JavaScript. Você deve saber o que são erros de sintaxe e tempo de execução e qual é a diferença entre eles.

Você também deve saber como a try...catchinstrução, e Finally, funciona, e como usá-la, executa seu código e captura os erros que ocorrerem. Você também sabe como lançar erros internos do JavaScript. Não apenas isso. Você também sabe como criar seus próprios erros com primitivas, construtores de funções e classes JavaScript.

E, se ocorrer algum erro em um escopo global, você saberá como usar o onerror()método ou o ouvinte de evento de erro para detectá-lo. Agora depende de você pegar o que aprendeu neste tutorial sobre tratamento de erros e usá-lo para escrever um código melhor e mais seguro.

Posted in Blog
Write a comment