我正在撰寫一個代碼,用于檢查 promise.all 方法中兩個不同 API 呼叫的授權,如果任何一個授權失敗,相應的 res.send 方法將作為錯誤拋出,但error : Cannot set headers after they are sent to the client我的控制臺上顯示錯誤,我哪里錯了?
在螢屏上,會顯示 res.send 陳述句,但與此同時,error : Cannot set headers after they are sent to the client我的控制臺上也會顯示此錯誤。我該如何解決 ?
我正在以兩種不同的方式撰寫代碼,但每次都顯示相同的錯誤。
第一種方式(沒有 .catch ):
const isSubscribed = new Promise((resolve, reject) => {
apiGet("/isSubscribed", token).then(async (Response) => {
if (!isResStatusSubscribed(Response)) return res.status(401).send({ errorMessage: "Unauthorized Request." })
})
})
const isAdmin = new Promise((resolve, reject) => {
apiGet("/isAdmin", token).then(async (response) => {
let isAdmin = response.data.Response.is_admin
if (!isAdmin) return res.status(403).send({ errorMessage: "User is not an Admin" })
})
})
Promise.all([isSubscribed, isAdmin]).then(async () => {
await insertLiveClassDB(req.body)
return res.status(200).send({ Response: "Success." })
});
第二種方式(使用 .catch ):
const isSubscribed = new Promise((resolve, reject) => {
apiGet("/isSubscribed", token).then(async (Response) => {
if (!isResStatusSubscribed(Response)) reject(res.status(401).send({ errorMessage: "Unauthorized Request." }))
})
})
const isAdmin = new Promise((resolve, reject) => {
apiGet("/isAdmin", token).then(async (response) => {
let isAdmin = response.data.Response.is_admin
if (!isAdmin) reject(res.status(403).send({ errorMessage: "User is not an Admin" }))
})
})
Promise.all([isSubscribed, isAdmin])
.then(async () => {
await insertLiveClassDB(req.body)
return res.status(200).send({ Response: "Success." })
})
.catch(error => {
return error
});
我是表達 js 和撰寫 promise.all 方法的新手,真的需要幫助。先感謝您。
uj5u.com熱心網友回復:
這里有很多問題。首先,您可以對每個傳入的 http 請求發送一個且只有一個回應。因此,您永遠不應該并行啟動多個異步操作并讓它們中的每一個都發送回應。相反,跟蹤兩個異步操作并在承諾完成Promise.all()時發送回應。Promise.all()
此外,您還有幾個 Promise 建構式反模式的示例,在這些示例中,您將新的 Promise 包裝在已經回傳 Promise 的函式周圍。出于多種原因,這被認為是一種反模式。不僅是不必要的額外代碼(你可以直接回傳你已經擁有的承諾),而且在錯誤處理中也容易出錯。
這是我的建議:
// stand-alone functions can be declared in a higher scope and
// used by multiple routes
const isSubscribed = function(token) {
return apiGet("/isSubscribed", token).then((Response) => {
if (!isResStatusSubscribed(Response)) {
// turn into a rejection
let e = new Error("Unauthorized Request");
e.status = 401;
throw e;
}
});
}
const isAdmin = function(token) {
return apiGet("/isAdmin", token).then((response) => {
let isAdmin = response.data.Response.is_admin
if (!isAdmin) {
// turn into a rejection
let e = new Error("User is not an Admin");
e.status = 403;
throw e;
}
});
}
// code inside your request handler which you already showed to be async
try {
await Promise.all([isSubscribed(token), isAdmin(token)]);
await insertLiveClassDB(req.body);
return res.status(200).send({ Response: "Success." });
} catch(e) {
let status = e.status || 500;
return res.status(status).send({errorMessage: e.message});
}
變更摘要:
將
isSubscribed()andisAdmin()變成一個回傳承諾的可重用函式。如果他們被訂閱或管理,則該承諾會解決,如果不是,則拒絕,如果 API 有錯誤,也會拒絕。如果這些函式獲得成功的 API 回應,但顯示它們沒有訂閱或不是管理員,那么它們將使用具有訊息集的自定義錯誤物件和具有
.status建議回應狀態的自定義屬性集來拒絕。如果這些函式沒有獲得成功的 API 回應(API 呼叫本身失敗),那么它將是任何錯誤物件
apiGet()拒絕。然后,
await Promise.all([isSubscribed(token), isAdmin(token)])如果它解決了,那么它通過了兩個測驗。如果它拒絕,那么它至少沒有通過一項測驗,并且拒絕將是首先失敗的那個。try/catch您可以使用 a以及來自 的任何拒絕來捕獲該拒絕insertLiveClassDB(req.body)。然后,catch處理程式可以在一個地方發送錯誤回應,保證您不會嘗試發送多個回應。如果 API 回應指示失敗,請注意兩者是如何測驗它們的回應
isSubscribed()并將isAdmin()回傳的承諾轉換為拒絕承諾的。throw e這允許呼叫代碼在一個代碼路徑中處理所有型別的故障。
uj5u.com熱心網友回復:
如果 isSubscribed 檢查失敗,則檢查 isAdmin 沒有意義,因此請按順序進行檢查。
通過在檢查失敗時拋出錯誤,這些或任何其他錯誤都可以由終端捕獲來處理。
我會寫這樣的東西:
apiGet("/isSubscribed", token)
.then(response => {
if (!isResStatusSubscribed(response)) {
throw Object.assign(new Error('Unauthorized Request'), { 'code':401 }); // throw an Error decorated with a 'code' property.
}
})
.then(() => {
// arrive here only if the isSubscribed check is successful.
return apiGet("/isAdmin", token)
.then(response => {
if (!response.data.Response.is_admin) {
throw Object.assign(new Error('User is not an Admin'), { 'code':403 }); // throw an Error decorated with a 'code' property.
}
});
})
.then(() => {
// arrive here only if the isSubscribed and isAdmin checks are successful.
return insertLiveClassDB(req.body));
}
.then(() => {
// arrive here only if the isSubscribed and isAdmin checks and insertLiveClassDB() are successful.
res.status(200).send({ 'Response': 'Success.' });
})
.catch(e) => {
// arrive here if anything above has thrown.
// e.code will be 401, 403 or undefined, depending of where the failure occurred.
res.status(e.code || 500).send({ 'errorMessage': e.message }); // 500 should be a reasonable default.
};
uj5u.com熱心網友回復:
我認為沒有必要Promise.all,性能提升將是微不足道的。如果需要,依次進行兩項檢查并在每次檢查后拋出錯誤會更容易,或者如果兩個條件都通過,則最終回應一次。但這是可行的:
const isSubscribed = async () => {
const response = await apiGet("/isSubscribed", token);
if (!isResStatusSubscribed(response)) throw { message : "Unauthorized Request.", status : 401 }; // Will be caught in the Promise.all catch block
}
const isAdmin = async () => {
const response = await apiGet("/isAdmin", token);
if (!isResStatusSubscribed(response)) throw { message : "User is not an Admin", status : 403 }; // Will be caught in the Promise.all catch block
}
(async () => {
try{
await Promise.all([isSubscribed(), isAdmin()]);
await insertLiveClassDB(req.body)
res.status(200).send({ Response: "Success." })
} catch(err) {
res.status(err.status).send({ errorMessage : err.message })
}
})();
Promise.all只失敗一次,只要任何一個 Promise 失敗。因此,catch即使兩個條件都拋出錯誤,該塊也只會被觸發一次。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/433147.html
標籤:javascript 节点.js 表示 承诺
上一篇:反應:在懸停(觸摸)時顯示元素,但防止在div內進行初始點擊
下一篇:只希望在獲取路線中回傳一項
