Правильный способ обработки обещаний и ответа сервера
Я пытаюсь улучшить свой код в node.js/sail.js, и я борюсь с ответом сервера в обещаниях.
Когда вы смотрите на первую функцию .then
, вы можете увидеть, что метод возвращает false
в случае forbidden access
или notFound
. Затем, в следующих функциях .then
, я должен проверить, является ли тип возврата === false
, чтобы перейти к разделу и избежать отправки заголовков HTTP дважды. Может ли это быть каким-то образом улучшено, чтобы пропустить все следующие методы .then
в случае сбоя? Я могу бросить исключение, чтобы перейти в последний .catch
, но тогда должно быть case
для переключения между всеми возможными состояниями. (т.е. запрещено, serverError или даже не найден)
Notification.findOne({id: req.param('id')})
.then(function(notification) {
if (!notification) {
res.notFound();
return false;
}
if (notification.triggeredBy != req.session.user.id) {
res.forbidden();
return false;
}
return notification;
})
.then(function(notification) {
if (notification === false) {
return false;
}
return Notification.update(notification.id, actionUtil.parseValues(req));
})
.then(function(notification) {
if (notification === false) {
return false;
}
res.json(notification);
})
.catch(function(err) {
sails.log(err);
res.serverError({message: 'A server error occurred.'});
})
Ответы
Ответ 1
Если бы я сделал это, сначала я отдельная логика и функция получения/отправки. Во-вторых, я указываю список кодов ошибок. И это будет так:
NotificationService.js
/*
Listing of error codes: {
* [1] Object not found
* [2] Forbidden
* [3] Server error
}
*/
module.exports = {
nameOfMethod: function(ID, sessionID) {
return new Promise(function(resolve, reject) {
Notification.findOne({ id: ID })
.then(function(notification) {
if (!notification) return reject({ error_code: 1 });
if (notification.triggeredBy !== sessionID) return reject({ error_code: 2 });
Notification.update(notification.id, actionUtil.parseValues(req))
.then(function(notification) {
return resolve(notification); // finally return our notification
})
.catch(function(err) {
sails.log.error(err); // It good when log is classified. In this case is error
return reject({ message: 'A server error occurred.' });
});
})
.catch(function(err) {
sails.log.error(err);
return reject({ message: 'A server error occurred.' });
});
});
}
};
NotificationController.js
module.exports = {
notifyMe: function(req, res) {
const ID = req.param('id'), sessionID = req.session.user.id;
NotificationService.nameOfMethod(ID, sessionID)
.then(function(notification) {
return res.send(notification);
})
.catch(function(err) {
switch (err.error_code) {
case 1:
return res.notFound(err);
case 2:
return res.forbidden(err);
default:
return res.serverError(err);
}
});
}
};
В случае, когда я использую переключатель, я думаю, что это лучший способ выбрать правильный ответ, но в это время я понятия не имею
Ответ 2
Посмотрите, как в Bluebird реализовано отфильтрованное .catch()
- в вашем случае может оказаться полезным все необходимые вам ошибки, но избегайте использования большого блока переключателя/случая в обработчике catch
:
.catch(
class ErrorClass|function(any error)|Object predicate...,
function(any error) handler
) -> Promise
.caught(
class ErrorClass|function(any error)|Object predicate...,
function(any error) handler
) -> Promise
Это расширение для .catch, чтобы работать больше как catch-clauses в таких как Java или С#. Вместо ручной проверки instanceof или .name === "SomeError", вы можете указать ряд конструкторов ошибок которые подходят для этого обработчика улова. Обработчик уловов, который первый встреченный, который имеет соответствующие конструкторы, указан, тот, который будет вызываться.
Пример:
somePromise.then(function() {
return a.b.c.d();
}).catch(TypeError, function(e) {
//If it is a TypeError, will end up here because
//it is a type error to reference property of undefined
}).catch(ReferenceError, function(e) {
//Will end up here if a was never declared at all
}).catch(function(e) {
//Generic catch-the rest, error wasn't TypeError nor
//ReferenceError
});
Смотрите: http://bluebirdjs.com/docs/api/catch.html#filtered-catch
Вместо:
return false;
вы можете использовать:
return Promise.reject(someReason);
или
throw someReason;
и вам не нужно будет проверять эти значения false
- просто используйте (возможно, несколько) обработчиков catch
.