Error: Callback was already called in loopback
Error: Callback was already called in loopback
我有以下代码:
"use strict";
const Raven = require("raven");
Raven.config(
"test"
).install();
module.exports = function(Reservation) {
function dateValidator(err) {
if (this.startDate >= this.endDate) {
err();
}
}
function sendEmail(campground) {
return new Promise((resolve, reject) => {
Reservation.app.models.Email.send(formEmailObject(campground),
function(
err,
mail
) {
if (err) {
console.log(err);
Raven.captureException(err);
reject(err);
} else {
console.log(mail);
console.log("email sent!");
resolve(mail);
}
});
});
}
function formEmailObject(campground) {
return {
to: "loopbackintern@yopmail.com",
from: "noreply@optis.be",
subject: "Thank you for your reservation at " + campground.name,
html:
"<p>We confirm your reservation for <strong>" +
campground.name +
"</strong></p>"
};
}
Reservation.validate("startDate", dateValidator, {
message: "endDate should be after startDate"
});
Reservation.observe("after save", async function(ctx, next) {
try {
const campground = await Reservation.app.models.Campground.findById(
ctx.instance.campgroundId
);
const mail = await sendEmail(campground);
next();
} catch (e) {
Raven.captureException(e);
next(e);
}
});
};
抱歉格式不正确。流程完成后出现此错误:
(node:3907) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Callback was already called.
我在两个地方调用 next() 回调,一个在 try 代码中,一个在 catch 代码中。我假设当一切顺利时,下一个回调只被调用一次,当它出错时也是如此。但是好像调用了两次不知道为什么。
我也尝试在 try/catch 代码之外调用 next,但它导致了同样的错误。如果我只留下在捕获代码中调用的下一个,它不会抛出错误。
有什么想法吗?谢谢!
您应该将 sendEmail 方法声明为异步的,因为它 returns 是一个承诺。
异步函数发送电子邮件(营地){
...
}
如果您使用的是异步函数,则不应显式调用 next,它 会自动调用。
check out this github issue for loopback async/await
所以你的钩子可以像下面这样。
Reservation.observe("after save", async ctx => {
try {
const campground = await Reservation.app.models.Campground.findById(
ctx.instance.campgroundId
);
const mail = await sendEmail(campground);
} catch (e) {
Raven.captureException(e);
throw e;
}
});
注意:你不需要将它包装在 try catch 中,除非你想 modify/work 处理错误。
阅读 this article 后,我创建了一个 await-handler.js 文件,其中包含以下代码。
module.exports = (promise) =>
promise
.then(data => ({
ok: true,
data
}))
.catch(error =>
Promise.resolve({
ok: false,
error
})
);
然后在 MyModel.js 文件中,我创建了一个异步函数来从数据库中获取值,如下所示。
const awaitHandler = require("./../await-handler.js")
const getMaxNumber = async (MyModel) => {
let result = await awaitHandler(MyModel.find());
if (result.ok) {
if (result.data.length) {
return result.data.reduce((max, b) => Math.max(max, b.propertyName), result.data[0] && result.data[0].propertyName);
} else {
return 0;
}
} else {
return result.error;
}
}
根据@Mehari 的回答,我评论了对 next()
方法的调用如下:-
module.exports = function(MyModel) {
MyModel.observe('before save', async(ctx, next) => {
const maxNumber = await getMaxNumber (MyModel);
if(ctx.instance) {
...
set the required property using ctx.instance.*
like createdAt, createdBy properties
...
// return next();
} else {
...
code for patch
...
// return next();
}
})
}
这解决了每当触发保存端点时的警告问题。
但是当我 运行 端点加载 resource.Like 时警告问题仍然出现
http://localhost:3000/api/MyModel
以前,只有当 before save
操作挂钩被触发时才会出现此问题。
遇到这个问题后,我检查了添加 access
和 loaded
操作挂钩,发现警告是在 loaded
操作挂钩之后发出的。
MyModel.observe('access', (ctx, next) => {
return next();
})
MyModel.observe('loaded', (ctx, next) => {
return next();
})
是什么原因导致了这个问题,如何解决?
我有以下代码:
"use strict";
const Raven = require("raven");
Raven.config(
"test"
).install();
module.exports = function(Reservation) {
function dateValidator(err) {
if (this.startDate >= this.endDate) {
err();
}
}
function sendEmail(campground) {
return new Promise((resolve, reject) => {
Reservation.app.models.Email.send(formEmailObject(campground),
function(
err,
mail
) {
if (err) {
console.log(err);
Raven.captureException(err);
reject(err);
} else {
console.log(mail);
console.log("email sent!");
resolve(mail);
}
});
});
}
function formEmailObject(campground) {
return {
to: "loopbackintern@yopmail.com",
from: "noreply@optis.be",
subject: "Thank you for your reservation at " + campground.name,
html:
"<p>We confirm your reservation for <strong>" +
campground.name +
"</strong></p>"
};
}
Reservation.validate("startDate", dateValidator, {
message: "endDate should be after startDate"
});
Reservation.observe("after save", async function(ctx, next) {
try {
const campground = await Reservation.app.models.Campground.findById(
ctx.instance.campgroundId
);
const mail = await sendEmail(campground);
next();
} catch (e) {
Raven.captureException(e);
next(e);
}
});
};
抱歉格式不正确。流程完成后出现此错误:
(node:3907) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Callback was already called.
我在两个地方调用 next() 回调,一个在 try 代码中,一个在 catch 代码中。我假设当一切顺利时,下一个回调只被调用一次,当它出错时也是如此。但是好像调用了两次不知道为什么。
我也尝试在 try/catch 代码之外调用 next,但它导致了同样的错误。如果我只留下在捕获代码中调用的下一个,它不会抛出错误。
有什么想法吗?谢谢!
您应该将 sendEmail 方法声明为异步的,因为它 returns 是一个承诺。
异步函数发送电子邮件(营地){ ... }
如果您使用的是异步函数,则不应显式调用 next,它 会自动调用。
check out this github issue for loopback async/await
所以你的钩子可以像下面这样。
Reservation.observe("after save", async ctx => {
try {
const campground = await Reservation.app.models.Campground.findById(
ctx.instance.campgroundId
);
const mail = await sendEmail(campground);
} catch (e) {
Raven.captureException(e);
throw e;
}
});
注意:你不需要将它包装在 try catch 中,除非你想 modify/work 处理错误。
阅读 this article 后,我创建了一个 await-handler.js 文件,其中包含以下代码。
module.exports = (promise) =>
promise
.then(data => ({
ok: true,
data
}))
.catch(error =>
Promise.resolve({
ok: false,
error
})
);
然后在 MyModel.js 文件中,我创建了一个异步函数来从数据库中获取值,如下所示。
const awaitHandler = require("./../await-handler.js")
const getMaxNumber = async (MyModel) => {
let result = await awaitHandler(MyModel.find());
if (result.ok) {
if (result.data.length) {
return result.data.reduce((max, b) => Math.max(max, b.propertyName), result.data[0] && result.data[0].propertyName);
} else {
return 0;
}
} else {
return result.error;
}
}
根据@Mehari 的回答,我评论了对 next()
方法的调用如下:-
module.exports = function(MyModel) {
MyModel.observe('before save', async(ctx, next) => {
const maxNumber = await getMaxNumber (MyModel);
if(ctx.instance) {
...
set the required property using ctx.instance.*
like createdAt, createdBy properties
...
// return next();
} else {
...
code for patch
...
// return next();
}
})
}
这解决了每当触发保存端点时的警告问题。
但是当我 运行 端点加载 resource.Like 时警告问题仍然出现
http://localhost:3000/api/MyModel
以前,只有当 before save
操作挂钩被触发时才会出现此问题。
遇到这个问题后,我检查了添加 access
和 loaded
操作挂钩,发现警告是在 loaded
操作挂钩之后发出的。
MyModel.observe('access', (ctx, next) => {
return next();
})
MyModel.observe('loaded', (ctx, next) => {
return next();
})
是什么原因导致了这个问题,如何解决?