Obsługa określonych błędów w JavaScript (pomyśl o wyjątkach)

112

Jak zaimplementowałbyś różne typy błędów, abyś był w stanie wyłapać konkretne i pozwolić innym się rozwijać ...?

Jednym ze sposobów osiągnięcia tego jest zmodyfikowanie prototypu Errorobiektu:

Error.prototype.sender = "";


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

    e.sender = "specific";

    throw e;
}

Błąd związany z połowem:

try
{
    throwSpecificError();
}

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

    // handle specific error
}


Czy macie jakieś alternatywy?

cllpse
źródło

Odpowiedzi:

159

Aby utworzyć niestandardowe wyjątki, możesz dziedziczyć po obiekcie 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
  }
}

Minimalistyczne podejście, bez dziedziczenia po Error, mogłoby polegać na wyrzuceniu prostego obiektu o nazwie i właściwościach wiadomości:

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
  }
}
CMS
źródło
2
Dziedziczenie z Errorma problemy. Zobacz stackoverflow.com/questions/1382107/…
Crescent Fresh,
5
problem z tym kodem } catch (e) { if (e.name == 'SpecificError') { // specific error } else { throw e; // let others bubble up } }polega na tym, że nie będzie on działał w IE7, powodując błąd „Zgłoszono wyjątek i nie został przechwycony”. Poniżej znajduje się wyjątkowo głupie (jak zawsze) wyjaśnienie z msdn: „Zawarłeś instrukcję rzut, ale nie została ona ujęta w bloku try lub nie było skojarzonego bloku catch, który mógłby przechwycić błąd. Wyjątki są wyrzucane z bloku try używając instrukcji throw i przechwyconej poza blok try za pomocą instrukcji catch. "
Eugene Kuzmenko,
1
C # C # Microsoftu z pewnością obsługuje błędy lepiej niż Javascript: P. Mozzilla dodała coś podobnego do Firefoksa. Chociaż nie jest to standard Ecmascript, nawet ES6, ale wyjaśniają również, jak go dostosować, chociaż nie jest to tak soczyste. Zasadniczo to samo, co powyżej, ale używając instanceOf. Sprawdź tutaj
Bart
W JavaScript możesz wrzucić cokolwiek zechcesz, czy to prosty ciąg znaków, liczbę (pomyśl o kodzie błędu), czy w pełni kwalifikowany obiekt. Słodkie!
Abraham Brookes,
1
@LuisNell, Jeśli przyjrzysz się uważnie mojemu przykładowi kodu, zobaczysz, że nie sugerowałem używania namewłaściwości funkcji konstruktora. Sugerowałem wrzucenie niestandardowego przedmiotu z namewłaściwością, która się nie zepsuje ...
CMS
15

Jak zauważono w komentarzach poniżej, jest to specyficzne dla Mozilli, ale można użyć bloków typu „catch warunkowy”. na przykład:

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

Daje to coś bardziej zbliżonego do obsługi wyjątków typowych używanej w Javie, przynajmniej składniowo.

Andy
źródło
Połącz z odpowiedzią CMS i jest doskonały.
Ates Goral
3
Łap warunkowy to coś, czego wcześniej nie wiedziałem lub o czym zapomniałem. Dzięki za edukację / przypomnienie mi! +1
Ates Goral
12
Obsługiwane tylko przez przeglądarkę Firefox (od wersji 2.0). Nie analizuje go nawet w innych przeglądarkach; otrzymujesz tylko błędy składniowe.
Crescent Fresh
10
Tak, to jest rozszerzenie tylko do Mozilli, nie jest nawet proponowane do standaryzacji. Ponieważ jest to funkcja na poziomie składni, nie ma sposobu, aby ją podsłuchać i opcjonalnie jej użyć.
bobince
3
Dodatkowo z uwagi na to, że proponowane rozwiązanie jest niestandardowe. Cytuj z [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

Używając try-catch-final.js , możesz wywołać _tryfunkcję z anonimowym wywołaniem zwrotnym, które będzie wywołać, i możesz łączyć .catchwywołania w celu wychwycenia określonych błędów oraz .finallywywołanie do wykonania w obie strony.

Przykład

_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');
});

Przykład z nowoczesnymi funkcjami strzałek i literałami szablonów

_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');
});
c24w
źródło
2

Moduł do wykorzystania na eksport

/**
 * 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
};

Importuj do skryptu:

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

Posługiwać się:

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

Kod telefoniczny zewnętrzny:

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');
  }
});
Hoovinator
źródło
0

Nie podobało mi się żadne z tych rozwiązań, więc stworzyłem własne. Try-catch-final.js jest całkiem fajny, z wyjątkiem tego, że jeśli zapomnisz jednego małego podkreślenia (_) przed próbą, kod nadal będzie działał dobrze, ale nic nie zostanie złapane! Fuj.

CatchFilter

Dodałem CatchFilter do mojego kodu:

"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;
    }
  };
};

Teraz mogę filtrować

Teraz mogę filtrować jak w C # lub Javie:

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.");
});
Ryan Shillington
źródło
-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);
  }
carls eriksen
źródło
Cześć, witaj w StackOverflow. W jaki sposób Twoja odpowiedź jest lepsza / wydajniejsza / itp. Z pozostałych 5 odpowiedzi już opublikowanych?
mjuarez