如何优雅的解决循环里的异步查询?
发布于 8 年前 作者 weapon-xx 5044 次浏览 来自 问答

最近项目里有个问题一直困扰了我挺久的,需要在循环里去查找数据库,把查询到的数据push到一个数组里,并且在循环完成后才返还,现在我想到的是在循环里面加入了个立即执行函数,将循环变量传入立即执行函数,除此之外还有其他好的写法吗?,还有我如何知道这个循环什么时候完成了呢? 伪代码: var results; for(var i=0;i<docs.length;i++){ (function(i){ db.findOne({_id : docs[i]._id},function(err,collection){ results.push(collection); }) }){i} } res.end(JSON.stringify(results)); //[] 希望有大大给我解决下困惑,非常感谢

12 回复

请使用异步流程控制库:async,peomise 等

来自酷炫的 CNodeMD

把数据库操作放进循环通常不是好办法,是不是异步和这没有关系。更优雅的实现是一次性把ID序列传进一词数据库操作,如果能findOne,自然应该有findMany。

@o6875461 现在项目里有用到,但是还是不能很好解决问题呢

@flamingtop 嗯嗯,是我的思路存在问题,要回去重构代码了,非常感谢你的回答

@weapon-xx 笑了,请查看async.map方法,或promise的map方法,如果还无法解决,请无视

来自酷炫的 CNodeMD

使用闭包方法,能够解决循环里的异步问题

使用Promise吧

function promise(id) {
	return new Promise(function (reslove, reject) {
    	db.findOne({_id: id._id}, function (err, collection) {
        	if (err) {
            	return reject(err);
        	}
        	resolve(collection);
    	});
	});
}
let arr = docs.map(item=>promise(docs[item]));
Promise.all(arr).then(results=>res.end(JSON.stringify(results))).catch(err=>console.error(err));

或者用Generator函数,更加接近常用的逻辑

function _gen(req, res, next) {
	let results = [];
	for (let i = 0; i < docs.length; i++) {
    	let resTmp = yield promiseFindOne(docs[i]._id);
    	results.push(resTmp);
	}
	res.end(JSON.stringify(results));
}
app.get('/', function (req, res, next) {
	require('co')(_gen, req, res, next).catch(err=>next(err));
});

@hyj1991 赞,学习了:)

@liuxufei 感谢,用eventproxy实现,代码好看多了

最好的方式,后期扩展维护最好的应该是 co.js

回到顶部