Javascript 快车中的异步地狱
我有一个问题是由于使用了异步而导致的,但事情不同步(是的,我知道这很常见),它看起来是这样的: 首先,express路由器从url获取调用,然后调用Middleware函数Javascript 快车中的异步地狱,javascript,node.js,express,Javascript,Node.js,Express,我有一个问题是由于使用了异步而导致的,但事情不同步(是的,我知道这很常见),它看起来是这样的: 首先,express路由器从url获取调用,然后调用Middleware函数 router.post('/', checkFunction, (req, res, next) => { res.render('somepage.ejs', { output: res.locals.output; }); }); 现在,在checkFunction(过去仅为回调函
router.post('/', checkFunction, (req, res, next) => {
res.render('somepage.ejs', {
output: res.locals.output;
});
});
现在,在checkFunction(过去仅为回调函数)中,我现在调用另一个使用axios且必须是异步的函数
function checkFunction(req, res, next) {
if ('check') secondFunction(req, res, next);
next()
}
最后一个函数如下所示,它检查来自用户页面的输入是否有空字符串、好的请求和坏的请求,并将输出返回给用户,不管是空的好的还是坏的。
在错误的日志上,它执行tail命令从日志中获取有关错误的数据
async function secondFunction(req, res, next) {
const url = 'http://somepage.com';
if ('some check on req') res.locals.output = 'nothing';
else {
try {
const data = await axios.get(url);
res.locals.output = 'good request';
} catch (error) {
exec(`tail -n 1 file.log`, (error, stdout, stderr) => {
console.log('err:', error);
console.log('stdout:', stdout);
console.log('stderr:', stderr);
res.locals.output = stdout;
});
}
}
}
问题是(正如预期的那样)第二个函数在axios请求完成之前运行,让output\exec命令也在等待它,然后check函数以未定义结束,因为输出尚未设置,同样的结果会一直返回给获得空页面的用户
现在我已经尝试了很多来自谷歌的combo与wait\async、promissions和其他巫术,但没有一个能帮助它正确同步,我想我需要做出连锁承诺来让它同步,但我不知道具体是如何实现的,因为check函数也被其他路由使用,它是一个通用函数,我真的不想为了处理这种奇怪的情况而复制代码
好了,就这样吧,非常感谢您的帮助。我正在用两个选项和错误处理修改我的答案。您可以通过两种方式等待“secondFunction”执行
async function checkFunction(req, res, next) {
if('check') {
try{
await secondFunction(req, res, next);
next();
}catch(ex) {
throw new Error('Error', ex);
}
}else{
next(); //or throw error or redirect
}
}
async function secondFunction(req, res, next) {
const url = 'http://somepage.com';
if ('some check on req') res.locals.output = 'nothing';
else {
try {
const data = await axios.get(url);
res.locals.output = 'good request';
} catch (error) {
await new Promise((resolve, reject) => {
exec(`tail -n 1 file.log`, (error, stdout, stderr) => {
if(error) {
console.log('err:', error);
reject(error);
}else {
console.log('stdout:', stdout);
console.log('stderr:', stderr);
res.locals.output = stdout;
resolve();
}
});
});
}
}
}
选项2:使用回调
function checkFunction(req, res, next) {
if('check') {
secondFunction(req, res, (err) => {
if(err) {
//or throw error or redirect
}else{
next();
}
});
}else{
next(); //or throw error or redirect
}
}
function secondFunction(req, res, callback) {
const url = 'http://somepage.com';
if ('some check on req') {
res.locals.output = 'nothing';
callback();
} else {
axios.get(url).then((response) => {
res.locals.output = 'good request';
callback();
}).catch(err => {
exec(`tail -n 1 file.log`, (error, stdout, stderr) => {
if (error) {
console.log('err:', error);
callback(error);
} else {
console.log('stdout:', stdout);
console.log('stderr:', stderr);
res.locals.output = stdout;
callback();
}
});
});
}
}
另外,child_process.execSync()方法通常与child_process.exec()相同,只是在子进程完全关闭之前,该方法不会返回
var logs = execSync(`tail -n 1 file.log`);
console.log(logs);
但请注意,这将阻止您的IO操作。我正在使用两个选项和错误处理修改我的答案。您可以通过两种方式等待“secondFunction”执行
async function checkFunction(req, res, next) {
if('check') {
try{
await secondFunction(req, res, next);
next();
}catch(ex) {
throw new Error('Error', ex);
}
}else{
next(); //or throw error or redirect
}
}
async function secondFunction(req, res, next) {
const url = 'http://somepage.com';
if ('some check on req') res.locals.output = 'nothing';
else {
try {
const data = await axios.get(url);
res.locals.output = 'good request';
} catch (error) {
await new Promise((resolve, reject) => {
exec(`tail -n 1 file.log`, (error, stdout, stderr) => {
if(error) {
console.log('err:', error);
reject(error);
}else {
console.log('stdout:', stdout);
console.log('stderr:', stderr);
res.locals.output = stdout;
resolve();
}
});
});
}
}
}
选项2:使用回调
function checkFunction(req, res, next) {
if('check') {
secondFunction(req, res, (err) => {
if(err) {
//or throw error or redirect
}else{
next();
}
});
}else{
next(); //or throw error or redirect
}
}
function secondFunction(req, res, callback) {
const url = 'http://somepage.com';
if ('some check on req') {
res.locals.output = 'nothing';
callback();
} else {
axios.get(url).then((response) => {
res.locals.output = 'good request';
callback();
}).catch(err => {
exec(`tail -n 1 file.log`, (error, stdout, stderr) => {
if (error) {
console.log('err:', error);
callback(error);
} else {
console.log('stdout:', stdout);
console.log('stderr:', stderr);
res.locals.output = stdout;
callback();
}
});
});
}
}
另外,child_process.execSync()方法通常与child_process.exec()相同,只是在子进程完全关闭之前,该方法不会返回
var logs = execSync(`tail -n 1 file.log`);
console.log(logs);
但请注意,这将阻止您的IO操作。很抱歉,在发布问题时忘记添加下一个函数,checkFunction确实有它,因为它是一个中间件函数,但对于第二个函数,我不明白其意义,如果它不是中间件函数,它将返回checkFunction,我错了吗?好的,只是仔细检查一下,试试你的建议。我从路由的回调函数得到了更早的响应,所以我假设下一个函数也是一个异步函数,通过调用它,我实际上迫使它转到下一个不存在的中间件,因此它首先到达回调,然后按照执行顺序解析checkFunction和second函数……我做了一些工作对答案的修改。请看一看。
secondFunction()
将需要返回
或等待
您对exec()的承诺。实际上,secondFunction()
在exec()
完成后仍然无法进行通信。@nuwan niroshana谢谢!它最终可以根据需要工作。你不知道我花了多少时间在这件事上,以至于事实上我仍然不明白答案。哈哈。你能澄清一下我的想法吗:1。调用secondFunction()之后,我仍然看不到next()的意义,因为我说过checkFunction是一个全局中间件,所以在运行secondFunction的语句之后,它仍然有事情要做并运行,最后它运行next,在中间件完成之前运行next有什么原因吗?secondFunction只是一个可以在需要时使用的附加值。很抱歉,在发布问题时忘记添加下一个函数,checkFunction确实有它,因为它是一个中间件函数,但对于secondFunction,我不明白其意义,如果它不是中间件函数,它将返回checkFunction,我错了吗?好的,只是仔细检查一下,试试你的建议。我从路由的回调函数得到了更早的响应,所以我假设下一个函数也是一个异步函数,通过调用它,我实际上迫使它转到下一个不存在的中间件,因此它首先到达回调,然后按照执行顺序解析checkFunction和second函数……我做了一些工作对答案的修改。请看一看。secondFunction()
将需要返回
或等待
您对exec()的承诺。实际上,secondFunction()
在exec()
完成后仍然无法进行通信。@nuwan niroshana谢谢!它最终可以根据需要工作。你不知道我花了多少时间在这件事上,以至于事实上我仍然不明白答案。哈哈。你能澄清一下我的想法吗:1。调用secondFunction()之后,我仍然看不到next()的意义,因为我说过checkFunction是一个全局中间件,所以在运行secondFunction的语句之后,它仍然有事情要做并运行,最后它运行next,在中间件完成之前运行next有什么原因吗?secondFunction只是一个附加值,可以在需要时使用。