我无法理解JavaScript中的异步性。我认为我的代码应在我评论过的地方停止(转到if处),但是会引发错误:
未处理的拒绝错误:发送标头后无法设置。
很抱歉获得如此大的代码,但我想发送所有信息以使情况非常清楚。
我认为我的方法setTransferHistory(...)
和sendAuthorizationKey(...)
应该是异步/等待的,并且在完成此代码后,我想返回状态200。
Transaction.findOne({
where: {
id_sender: senderId,
id_recipient: recipientId,
amount_money: amountMoney,
transfer_title: transferTitle,
authorization_key: authorizationKey,
authorization_status: setAuthorizationStatus(0),
},
order: [['date_time', 'DESC']],
}).then(isAuthorizationKey => {
if (!isAuthorizationKey) {
setTransferHistory(
senderId,
recipientId,
amountMoney,
transferTitle,
authorizationKey,
);
sendAuthorizationKey(
senderId,
recipientId,
amountMoney,
authorizationKey,
);
return res.status(200).json({ success: true }); /* it should stop in this place */
}
所有控制器:
exports.register = (req, res) => {
function getTodayDate() {
const today = new Date();
return today;
}
function setAuthorizationStatus(status) {
const authorizationStatus = status;
return authorizationStatus;
}
async function getSenderEmail(id) {
try {
const isUser = await User.findOne({
where: {
id,
},
});
return isUser.email;
} catch (e) {
/* just ignore */
}
}
async function getRecipientName(id) {
try {
const isUser = await User.findOne({
where: {
id,
},
});
return `${isUser.name} ${isUser.surname}`;
} catch (e) {
/* just ignore */
}
}
function setAuthorizationKey() {
let authorizationKey = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
for (let i = 0; i < 5; i++)
authorizationKey += possible.charAt(
Math.floor(Math.random() * possible.length),
);
return authorizationKey;
}
async function sendAuthorizationKey(
senderId,
recipientId,
amountMoney,
authorizationKey,
) {
await nodemailer.createTestAccount();
const transporter = nodemailer.createTransport({
host: env.nodemailer.host,
port: env.nodemailer.port,
secure: false,
auth: {
user: env.nodemailer.username,
pass: env.nodemailer.password,
},
});
const mailOptions = {
from: "example"`,
to: `${await getSenderEmail(senderId)}`,
subject: 'example',
text: 'example`,
};
await transporter.sendMail(mailOptions);
}
function setTransferHistory(
senderId,
recipientId,
amountMoney,
transferTitle,
authorizationKey,
) {
Transaction.create({
id_sender: senderId,
id_recipient: recipientId,
date_time: getTodayDate(),
amount_money: amountMoney,
transfer_title: transferTitle,
authorization_key: authorizationKey,
authorization_status: setAuthorizationStatus(0),
});
}
Bill.findOne({
where: {
account_bill: req.body.account_bill,
},
}).then(isAccountBill => {
if (isAccountBill) {
const recipientId = isAccountBill.id_owner;
const authorizationKey = setAuthorizationKey();
const senderId = req.body.id_sender;
const amountMoney = req.body.amount_money;
const transferTitle = req.body.transfer_title;
if (recipientId !== senderId) {
Bill.findOne({
where: {
id_owner: senderId,
},
}).then(isAvailableFunds => {
if (isAvailableFunds) {
const senderAvailableFunds = isAvailableFunds.available_funds;
if (senderAvailableFunds >= amountMoney && amountMoney > 0) {
Transaction.findOne({
where: {
id_sender: senderId,
id_recipient: recipientId,
amount_money: amountMoney,
transfer_title: transferTitle,
authorization_key: authorizationKey,
authorization_status: setAuthorizationStatus(0),
},
order: [['date_time', 'DESC']],
}).then(isAuthorizationKey => {
if (!isAuthorizationKey) {
setTransferHistory(
senderId,
recipientId,
amountMoney,
transferTitle,
authorizationKey,
);
sendAuthorizationKey(
senderId,
recipientId,
amountMoney,
authorizationKey,
);
return res.status(200).json({ success: true }); /* it should stop in this place */
}
return res.status(400).json({
error: 'Authorization key has been sent',
success: false,
});
});
}
return res.status(400).json({
error: 'Sender does not have enough money',
success: false,
});
}
return res
.status(404)
.json({ error: 'Id sender doesnt exist', success: false });
});
}
return res
.status(404)
.json({ error: 'Attempt payment to myself', success: false });
}
return res
.status(404)
.json({ error: 'Recipient does not exist', success: false });
});
};
答案 0 :(得分:0)
在Promise回调中调用return
也不会从调用代码中返回。这是简化示例中的代码
if (someCondition) {
doSomethingAsync().then(() =>
...
return res.status(200).json(...);
});
}
return res.status(400).json(...);
现在给定doSomethingAsync
是异步的,您正在传递一个回调函数(then
),以便在I / O绑定过程完成时得到通知。但是,在进行此调用的同时,当前代码仍将运行完成,因此将非故意地调用return res.status(400).json(...)
,这意味着在为I / O绑定操作触发回调时,您已经结束了请求,因此收到适当的错误。
要解决此问题,您需要先等待异步代码完成,然后再继续执行 ,这正是async
/ await
设计的目的
if (someCondition) {
await doSomethingAsync();
return res.status(200).json(...);
}
return res.status(400).json(...);
注意-您的代码中确实有一些场景,其中您调用async
函数,但没有await
函数,例如sendAuthorizationKey
,不确定这是否是故意的,但确实意味着代码很可能在其余代码执行之前无法完成