Szukaj…


Obsługa wyjątku w Node.Js

Node.js ma 3 podstawowe sposoby obsługi wyjątków / błędów:

  1. spróbuj złapać blok
  2. błąd jako pierwszy argument callback
  3. emit zdarzenie błędu za pomocą eventEmitter

try-catch służy do wychwytywania wyjątków zgłaszanych podczas synchronicznego wykonywania kodu. Jeśli osoba dzwoniąca (lub osoba dzwoniąca, ...) zastosowała try / catch, może złapać błąd. Jeśli żaden z rozmówców nie próbował złapać, program ulega awarii.
Jeśli użycie try-catch w operacji asynchronicznej spowoduje zgłoszenie wyjątku z wywołania zwrotnego metody asynchronicznej, wówczas nie zostanie on złapany przez try-catch. Aby wychwycić wyjątek od wywołania zwrotnego operacji asynchronicznej, zaleca się stosowanie obietnic .
Przykład, aby lepiej to zrozumieć

// ** Example - 1  **
function doSomeSynchronousOperation(req, res) {
    if(req.body.username === ''){
        throw new Error('User Name cannot be empty');
    }  
    return true;  
}

// calling the method above
try {
    // synchronous code   
    doSomeSynchronousOperation(req, res)    
catch(e) {
    //exception handled here   
    console.log(e.message);  
} 

// ** Example - 2 **
function doSomeAsynchronousOperation(req, res, cb) {
    // imitating async operation
    return setTimeout(function(){
        cb(null, []);
    },1000);
}
 
try {
    // asynchronous code   
    doSomeAsynchronousOperation(req, res, function(err, rs){
        throw new Error("async operation exception");
    })   
} catch(e) {
     // Exception will not get handled here
     console.log(e.message);  
}
// The exception is unhandled and hence will cause application to break

wywołania zwrotne są najczęściej używane w Node.js, ponieważ wywołanie zwrotne dostarcza zdarzenie asynchronicznie. Użytkownik przekazuje ci funkcję (wywołanie zwrotne) i wywołujesz ją później, gdy zakończy się operacja asynchroniczna.
Zwykle wzorzec polega na tym, że wywołanie zwrotne jest wywoływane jako wywołanie zwrotne (err, wynik) , przy czym tylko jedno z err i wynik ma wartość inną niż null, w zależności od tego, czy operacja się powiodła, czy nie.

function doSomeAsynchronousOperation(req, res, callback) {
   setTimeout(function(){
        return callback(new Error('User Name cannot be empty'));    
   }, 1000);  
   return true;
}

doSomeAsynchronousOperation(req, res, function(err, result) {
   if (err) {
       //exception handled here 
       console.log(err.message);
   }
   
   //do some stuff with valid data
});

emit W przypadku bardziej skomplikowanych przypadków, zamiast korzystania z wywołania zwrotnego, sama funkcja może zwrócić obiekt EventEmitter i oczekuje się, że osoba dzwoniąca będzie nasłuchiwała zdarzeń błędów na emiterze.

const EventEmitter = require('events');

function doSomeAsynchronousOperation(req, res) {
    let myEvent = new EventEmitter();

    // runs asynchronously
    setTimeout(function(){
        myEvent.emit('error', new Error('User Name cannot be empty'));
    }, 1000);

    return myEvent;
}

// Invoke the function
let event = doSomeAsynchronousOperation(req, res);

event.on('error', function(err) {
    console.log(err);
});

event.on('done', function(result) {
    console.log(result); // true
});

Zarządzanie nieobsługiwanymi wyjątkami

Ponieważ Node.js działa na jednym procesie, nieprzechwycone wyjątki stanowią problem, o którym należy pamiętać przy programowaniu aplikacji.

Cicha obsługa wyjątków

Większość osób pozwala serwerom node.js cicho połykać błędy.

  • Cicha obsługa wyjątku
process.on('uncaughtException', function (err) {
  console.log(err);
});

To źle , będzie działać, ale:

  • Przyczyna pierwotna pozostanie nieznana, ponieważ nie przyczyni się do rozwiązania przyczyny wyjątku (błędu).

  • W przypadku, gdy połączenie z bazą danych (pula) zostanie z jakiegoś powodu zamknięte, spowoduje to ciągłe propagowanie błędów, co oznacza, że serwer będzie działał, ale nie połączy się ponownie z db.


Powrót do stanu początkowego

W przypadku „nieprzechwyconego wyjątku” dobrze jest zrestartować serwer i przywrócić go do stanu początkowego , o którym wiemy, że będzie działał. Wyjątek jest rejestrowany, aplikacja zostaje zakończona, ale ponieważ będzie działała w kontenerze, który zapewni, że serwer działa, osiągniemy restart serwera (powrót do początkowego stanu roboczego).

  • Instalowanie na zawsze (lub inne narzędzie CLI, aby upewnić się, że serwer węzła działa nieprzerwanie)
npm install forever -g
  • Uruchamianie serwera na zawsze
forever start app.js

Powód, dla którego został uruchomiony i dlaczego używamy go na zawsze, następuje po tym, jak serwer zostanie zakończony na zawsze, proces uruchomi serwer ponownie.

  • Ponowne uruchomienie serwera
process.on('uncaughtException', function (err) {
    console.log(err);

    // some logging mechanisam
    // ....        

    process.exit(1); // terminates process
});

Na marginesie istniał również sposób radzenia sobie z wyjątkami z klastrami i domenami .

Domeny są przestarzałe, więcej informacji tutaj .

Błędy i obietnice

Obiecuje obsługiwać błędy inaczej niż kod synchroniczny lub kod wywołania zwrotnego.

const p = new Promise(function (resolve, reject) {
    reject(new Error('Oops'));
});

// anything that is `reject`ed inside a promise will be available through catch
// while a promise is rejected, `.then` will not be called
p
    .then(() => {
        console.log("won't be called");
    })
    .catch(e => {
        console.log(e.message); // output: Oops
    })
    // once the error is caught, execution flow resumes
    .then(() => {
        console.log('hello!'); // output: hello!
    });

obecnie błędy zgłoszone w obietnicy, która nie została złapana, powodują połknięcie błędu, co może utrudnić jego wyśledzenie. Można to rozwiązać za pomocą narzędzi do szorowania, takich jak eslint lub upewniając się, że zawsze masz klauzulę catch .

To zachowanie jest przestarzałe w węźle 8 na korzyść zakończenia procesu węzła.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow