[英]How do I handle an error and then immediately break out of a promise chain?
所以我有一個Express應用程序,它使用中間件來解析JSON POST請求,然后填充req.body
對象。 然后我有一個promise鏈,使用Joi對模式驗證數據,然后將其存儲在數據庫中。
我想要做的是檢查在這些進程之一之后是否拋出錯誤,通過發送狀態代碼來適當地處理它,然后完全拒絕承諾鏈。 我覺得應該有一些非常干凈和簡單的方法來做到這一點,(也許某種破壞聲明?)但我無法在任何地方找到它。 這是我的代碼。 我留下評論顯示我希望中止諾言鏈的地方。
const joi = require("joi");
const createUserSchema = joi.object().keys({
username: joi.string().alphanum().min(4).max(30).required(),
password: joi.string().alphanum().min(2).max(30).required(),
});
//Here begins my promise chain
app.post("/createUser", (req, res) => {
//validate javascript object against the createUserSchema before storing in database
createUserSchema.validate(req.body)
.catch(validationError => {
res.sendStatus(400);
//CLEANLY ABORT the promise chain here
})
.then(validatedUser => {
//accepts a hash of inputs and stores it in a database
return createUser({
username: validatedUser.username,
password: validatedUser.password
})
.catch(error => {
res.sendStatus(500);
//CLEANLY ABORT the promise chain here
})
//Only now, if both promises are resolved do I send status 200
.then(() => {
res.sendStatus(200);
}
)
});
你不能在中間中止一個承諾鏈。 它將在鏈中稍后調用.catch()
.then()
或.catch()
(假設有兩者並假設您的承諾解決或拒絕)。
通常,您處理此方法的方法是在鏈的末尾放置一個.catch()
,它會檢查錯誤的類型並采取適當的操作。 您不會在鏈中的早期處理錯誤。 你讓最后一個.catch()
處理事情。
這是我的建議:
// helper function
function err(status, msg) {
let obj = new Error(msg);
obj.status = status;
return obj;
}
//Here begins my promise chain
app.post("/createUser", (req, res) => {
//validate javascript object against the createUserSchema before storing in database
createUserSchema.validate(req.body).catch(validationError => {
throw err("validateError", 400)
}).then(validatedUser => {
//accepts a hash of inputs and stores it in a database
return createUser({
username: validatedUser.username,
password: validatedUser.password
}).catch(err => {
throw err("createUserError", 500);
});
}).then(() => {
// success
res.sendStatus(200);
}).catch(error => {
console.log(error);
if (error && error.status) {
res.sendStatus(error.status);
} else {
// no specific error status specified
res.sendStatus(500);
}
});
});
這有幾個好處:
.catch()
,並在代碼中的一個位置發送適當的狀態。 .catch()
,只需拒絕一個適當的錯誤對象)。 return value
語句的設計實踐,而是累積結果然后在最后返回它,有些人認為這是復雜函數的良好實踐。 .then()
和一個.catch()
看到許鏈的最終解決,因為整個產業鏈經過要么最后.then()
或最后.catch()
.catch
默認返回已解析的Promise 。 你想要一個被拒絕的Promsise 。 所以,你應該return
從里面被拒絕的承諾 .catch
,使未來的.then
旨意不執行:
.catch(validationError => {
res.sendStatus(400);
return Promise.reject();
})
但請注意,這將導致控制台警告:
未捕(承諾)......
所以最好在結尾添加另一個 .catch
,以抑制錯誤(以及捕獲任何其他錯誤):
const resolveAfterMs = ms => new Promise(res => setTimeout(() => { console.log('resolving'); res(); }), ms); console.log('start'); resolveAfterMs(500) .then(() => { console.log('throwing'); throw new Error(); }) .catch(() => { console.log('handling error'); return Promise.reject(); }) .then(() => { console.log('This .then should never execute'); }) .catch(() => void 0);
如果你想避免未來所有.then
S 和未來.catch
上課,我想你可以返回一個Promise
,從來沒有解決,雖然這並沒有真正聽起來像一個精心設計的代碼庫的跡象:
const resolveAfterMs = ms => new Promise(res => setTimeout(() => { console.log('resolving'); res(); }), ms); console.log('start'); resolveAfterMs(500) .then(() => { console.log('throwing'); throw new Error(); }) .catch(() => { console.log('handling error'); return new Promise(() => void 0); }) .then(() => { console.log('This .then should never execute'); }) .catch(() => { console.log('final catch'); });
您嘗試完成的更清晰的解決方案可能是使用快速驗證 ,這是一個簡單的joi包裝器,它為您提供快速中間件,用於驗證基於的快速請求的正文,參數,查詢,標題和cookie。你的Joi架構。
這樣,您可以簡單地處理“通用”快速錯誤處理程序中的中間件拋出的任何Joi驗證錯誤,例如:
const ev = require('express-validation');
app.use(function (err, req, res, next) {
// specific for validation errors
if (err instanceof ev.ValidationError)
return res.status(err.status).json(err);
...
...
...
}
一種策略是將子語句中的錯誤處理分開,這些子語句具有各自的錯誤處理。 如果你從它們拋出錯誤,你將繞過主要的承諾鏈。
就像是:
return Promise.resolve().then(() => {
return createUserSchema.validate(req.body)
.catch(validationError => {
res.sendStatus(400);
throw 'abort';
});
}).then(validatedUser => {
// if an error was thrown before, this code won't be executed
// accepts a hash of inputs and stores it in a database
return createUser({
username: validatedUser.username,
password: validatedUser.password
}).catch(error => {
// if an error was previously thrown from `createUserSchema.validate`
// this code won't execute
res.sendStatus(500);
throw 'abort';
});
}).then(() => {
// can put in even more code here
}).then(() => {
// it was not aborted
res.sendStatus(200);
}).catch(() => {
// it was aborted
});
您可以跳過Promise.resolve().then()
換行,但它是為了說明細分每個任務及其錯誤處理的一般模式而包含的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.