我有这个功能
/* GET main page */
router.get('/', (req, res, next) => {
Account.find({accType: 'Employer'}, (err, col) => {
if (err) {
console.log(err);
} else {
Banner.findOne((err, banner) => {
if (err) {
console.log(err);
} else {
// Determine whether there is at least one awaiting account.
Account.findOne({accType: 'Awaiting'}, (err, doc) => {
if (err) {
console.log(err);
} else {
if (doc != null) {
var awaiting = true;
}
console.log(doc);
res.render('admin/', {
title: 'Admin pannel',
user: req.user,
employers: col,
areAwaiting: awaiting,
banner: banner,
)
}
}
);
}
});
}
});
});
我尝试使用async模块,如下所示:
async.parallel(calls, (err, col) => {
if (err)
console.log(err);
else {
console.log(col);
res.render('admin/', {
title: 'Admin pannel',
user: req.user,
employers: col[0],
banner: col[1],
areAwaiting: col[2],
})
}
});
现在。我得到的错误是wrapAsync(...) is not a function。我尝试将我的函数放在这样的匿名函数中:
() => {
Account.find({accType: 'Employer'}, (err, col) => {
if (err)
console.log(err);
else return col;
})
}
然后代码就冻结了。我也试过这个:
(col) => {
Banner.findOne((err, doc) => {
if (err)
console.log(err);
else return doc;
});
return col
},
但效果相同。知道我做错了什么吗?回调地狱版本有效,但只是丑陋且无法维护。
Dave Meehan的回答。不得不稍微编辑它以使其工作。
router.get('/', (req, res) => {
return Promise.all([
Account.find(),
Banner.findOne(),
Account.findOne({accType: 'Awaiting'}),
]).then(([employers, banner, awaiting]) => { // Right here
if (awaiting != null)
var areAwaiting = true;
res.render('admin/', {
title: 'Admin pannel',
user: req.user,
employers: employers,
areAwaiting: areAwaiting,
banner: banner,
});
}).catch(e => {
console.error(e)
});
});
我必须将then
中的数组关闭到()
答案 0 :(得分:1)
总是可以通过不将其写为回调地狱来避免回调地狱。但在这种情况下,让我们先重写一些代码。
首先,如果收到错误,您可以提前纾困,因此无需在所有通话中使用else语句。这将为你删除很多范围。
因此,只需重写部分代码,就可以将其转换为如下所示:
router.get('/', (req, res, next) => {
getData((err, data) => {
if (err) return console.error(err)
res.render('admin/', { /* .. */ })
})
})
function getData (cb) {
Account.find({accType: 'Employer'}, (err, col) => {
if (err) return cb(err)
Banner.findOne((err, banner) => {
if (err) return cb(err)
Account.findOne({accType: 'Awaiting'}, (err, doc) => {
if (err) return cb(err)
cb(null, { col, banner, doc })
})
})
})
}
现在,让我们回到您对async
的使用,这在这里使用是个好主意,因为我真的不想拨打Account.find()
,Banner.findOne()
和Account.findOne()
按顺序。
你的问题在于你错误地使用async.parallel
,它假定一个函数的数组(或对象)进行回调。
这看起来如下:
async.parallel({
col: cb => Account.find({accType: 'Employer'}, cb),
banner: cb => Banner.findOne(cb),
doc: cb => Account.findOne({accType: 'Awaiting'}, cb)
}, (err, result) => {
// access result.col, result.banner and result.doc
})
现在我们可以在上面重构getData
,因此最终结果可能如下:
router.get('/', (req, res, next) => {
getData((err, data) => {
if (err) return console.error(err)
res.render('admin/', { /* data.doc, data.banner, data.doc */ })
})
})
function getData (cb) {
async.parallel({
col: cb => Account.find({accType: 'Employer'}, cb),
banner: cb => Banner.findOne(cb),
doc: cb => Account.findOne({accType: 'Awaiting'}, cb)
}, cb)
}
这看起来非常干净,并且确实没有必要使用Promises。
答案 1 :(得分:1)
这很简单,并假设:
您使用Express或类似的路由处理程序,并且您可以返回承诺而不是使用回调
您使用的是Mongoose或类似的数据库,可以返回承诺而不是使用回调。
检查您的版本是否支持Promise。
您似乎至少缺少Banner的一些查询参数,如果其中任何一个依赖,或者如图所示,它们可以并行运行,您需要确定它们。
router.get('/', (req, res) => {
return Promise.all([
Account.find(),
Banner.findOne(),
Account.findOne({ accType: 'Awaiting' }),
]).then(([ col, banner, doc ]) => {
res.render('admin/', {
title: 'Admin pannel',
user: req.user,
employers: col,
areAwaiting: awaiting,
banner: banner,
);
}).catch(e => { console.error(e) });
});