Tratamento de erros específicos em JavaScript (pense nas exceções)


112

Como você implementaria diferentes tipos de erros, para ser capaz de detectar alguns específicos e permitir que outros surgissem ...?

Uma maneira de conseguir isso é modificar o protótipo do Errorobjeto:

Error.prototype.sender = "";


function throwSpecificError()
{
    var e = new Error();

    e.sender = "specific";

    throw e;
}

Capture o erro específico:

try
{
    throwSpecificError();
}

catch (e)
{
    if (e.sender !== "specific") throw e;

    // handle specific error
}


Vocês têm alguma alternativa?

Respostas:


159

Para criar exceções personalizadas, você pode herdar do objeto Error:

function SpecificError () {

}

SpecificError.prototype = new Error();

// ...
try {
  throw new SpecificError;
} catch (e) {
  if (e instanceof SpecificError) {
   // specific error
  } else {
    throw e; // let others bubble up
  }
}

Uma abordagem minimalista, sem herdar de Error, poderia lançar um objeto simples com um nome e propriedades de mensagem:

function throwSpecificError() {
  throw {
    name: 'SpecificError',
    message: 'SpecificError occurred!'
  };
}


// ...
try {
  throwSpecificError();
} catch (e) {
  if (e.name == 'SpecificError') {
   // specific error
  } else {
    throw e; // let others bubble up
  }
}

2
Herdar de Errortem problemas. Consulte stackoverflow.com/questions/1382107/…
Crescent Fresh

5
o problema com este código: } catch (e) { if (e.name == 'SpecificError') { // specific error } else { throw e; // let others bubble up } }é que ele não funcionará no IE7, gerando o erro "Exceção lançada e não detectada". A seguir está a explicação extremamente estúpida (como sempre) do msdn: "Você incluiu uma instrução throw, mas ela não estava incluída em um bloco try, ou não havia bloco catch associado para detectar o erro. Exceções são lançadas de dentro do bloco try usando a instrução throw e capturado fora do bloco try com uma instrução catch. "
Eugene Kuzmenko

1
Bem, o C # da Microsoft certamente lida com erros melhor do que o Javascript: P. Mozzilla adicionou algo parecido ao Firefox que é assim. Embora não esteja no padrão Ecmascript, nem mesmo no ES6, eles também explicam como torná-lo compatível, embora não seja tão sucinto. Basicamente igual ao anterior, mas usando instanceOf. Verifique aqui
Bart de

Em Javascript você pode lançar o que quiser, seja uma string simples, um número (pense no código de erro) ou um objeto totalmente qualificado. Doce!
Abraham Brookes

1
@LuisNell, Se você olhar meu exemplo de código com atenção, verá que não estou sugerindo o uso da namepropriedade da função construtora. Eu estava sugerindo jogar um objeto feito sob encomenda com uma namepropriedade, que não vai quebrar ...
CMS

15

Conforme observado nos comentários abaixo, isso é específico do Mozilla, mas você pode usar blocos de 'captura condicional'. por exemplo:

try {
  ...
  throwSpecificError();
  ...
}
catch (e if e.sender === "specific") {
  specificHandler(e);
}
catch (e if e.sender === "unspecific") {
  unspecificHandler(e);
}
catch (e) {
  // don't know what to do
  throw e;
} 

Isso dá algo mais parecido com o tratamento de exceções digitadas usado em Java, pelo menos sintaticamente.


Combine com a resposta do CMS e é perfeito.
Ates Goral

3
A captura condicional é algo que eu não sabia antes ou esqueci. Obrigado por me educar / lembrar! +1
Ates Goral

12
Compatível apenas com Firefox (desde 2.0). Ele nem mesmo analisa em outros navegadores; você só obtém erros de sintaxe.
Crescent Fresh,

10
Sim, esta é uma extensão exclusiva do Mozilla, nem mesmo proposta para padronização. Por ser um recurso de nível de sintaxe, não há como farejar e, opcionalmente, usá-lo.
bobince

3
Como complemento, quanto à solução proposta não ser padronizada. Citação do [Mozilla's JavaScript Reference [( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ):This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.
informatik01

10

try-catch-finally.js

Usando try-catch-finally.js , você pode chamar a _tryfunção com um retorno de chamada anônimo, que será chamado, e pode encadear .catchchamadas para detectar erros específicos e uma .finallychamada para executar de qualquer maneira.

Exemplo

_try(function () {
    throw 'My error';
})
.catch(Error, function (e) {
    console.log('Caught Error: ' + e);
})
.catch(String, function (e) {
    console.log('Caught String: ' + e);
})
.catch(function (e) {
    console.log('Caught other: ' + e);
})
.finally(function () {
    console.log('Error was caught explicitly');
});

Exemplo com funções de seta modernas e literais de modelo

_try(() => {
  throw 'My error';
}).catch(Error, e => {
  console.log(`Caught Error: ${e}`);
}).catch(String, e => {
  console.log(`Caught String: ${e}`);
}).catch(e => {
  console.log(`Caught other: ${e}`);
}).finally(() => {
  console.log('Error was caught explicitly');
});

2

Módulo para uso de exportação

/**
 * Custom InputError
 */
class InputError extends Error {
  /**
   * Create InputError
   * @param {String} message
   */
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace(this, this.constructor);
  }
}

/**
 * Custom AuthError
 */
class AuthError extends Error {
  /**
   * Create AuthError
   * @param {String} message
   */
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace(this, this.constructor);
  }
}

/**
 * Custom NotFoundError
 */
class NotFoundError extends Error {
  /**
   * Create NotFoundError
   * @param {String} message
   */
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace(this, this.constructor);
  }
}

module.exports = {
  InputError: InputError,
  AuthError: AuthError,
  NotFoundError: NotFoundError
};

Importar para o script:

const {InputError, AuthError, NotFoundError} = require(path.join(process.cwd(), 'lib', 'errors'));

Usar:

function doTheCheck = () =>
  checkInputData().then(() => {
    return Promise.resolve();
  }).catch(err => {
    return Promise.reject(new InputError(err));
  });
};

Código de chamada externo:

doTheCheck.then(() => {
  res.send('Ok');
}).catch(err => {
  if (err instanceof NotFoundError) {
    res.status(404).send('Not found');
  } else if (err instanceof AuthError) {
    res.status(301).send('Not allowed');
  } else if (err instanceof InputError) {
    res.status(400).send('Input invalid');
  } else {
    console.error(err.toString());
    res.status(500).send('Server error');
  }
});

0

Não adorei nenhuma dessas soluções, então criei a minha. O try-catch-finally.js é muito legal, exceto que se você esquecer um pequeno sublinhado (_) antes de tentar, o código ainda funcionará perfeitamente, mas nada será detectado nunca! Que nojo.

CatchFilter

Eu adicionei um CatchFilter em meu código:

"use strict";

/**
 * This catches a specific error. If the error doesn't match the errorType class passed in, it is rethrown for a
 * different catch handler to handle.
 * @param errorType The class that should be caught
 * @param funcToCall The function to call if an error is thrown of this type
 * @return {Function} A function that can be given directly to the `.catch()` part of a promise.
 */
module.exports.catchOnly = function(errorType, funcToCall) {
  return (error) => {
    if(error instanceof errorType) {
      return funcToCall(error);
    } else {
      // Oops, it's not for us.
      throw error;
    }
  };
};

Agora posso filtrar

Agora posso filtrar como em C # ou Java:

new Promise((resolve, reject => {
   <snip><snip>
}).catch(CatchFilter.catchOnly(MyError, err =>
   console.log("This is for my error");
}).catch(err => {
   console.log("This is for all of the other errors.");
});

-2
    <li>
      <span>onWarning:</span>
      <span id="msg_warning"></span>
    </li>

  try {
  // load face detection model
  await changeFaceDetector(MTCNN)
  changeInputSize(128)

  // try to access users webcam and stream the images
  // to the video element

    const stream = await navigator.mediaDevices.getUserMedia({ video: {} })
    const videoEl = $('#inputVideo').get(0)
    videoEl.srcObject = stream
  }
  catch(err) {
    //$("#msg_error").html(`Requested device not found`);
    $("#msg_error").html(err.message);
    console.log(err.message);
  }

Olá, bem-vindo ao StackOverflow. Como sua resposta é melhor / mais eficiente / etc a partir das outras 5 respostas já postadas?
mjuarez
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.