Sail.js中如何异步获取所有函数结果?多查询顺序问题求助
看了你的代码和遇到的问题,核心bug出在你把async.series和forEach混用的逻辑上:forEach会一次性触发所有Model.count的异步调用,但你却只在「最后一个循环索引对应的异步回调」里调用counterCB——这就会导致:只要最后那个循环对应的数据库请求先完成,async.series就会提前结束流程,而其他还没跑完的请求结果根本来不及塞进counter数组,自然就会出现返回结果不全的情况。
举个例子:如果where_clauses有2个条件,i=1的请求先完成,你就会立刻调用counterCB,此时i=0的请求还在跑,counter里只有第二个结果;等i=0的请求完成后再push值,已经晚了,因为async.series的最终回调早就执行完并返回了。
下面给你三种靠谱的解决方案,按需选择:
方案1:用async.map(并行执行,自动收集结果)
async.map是专门为数组异步操作设计的工具,它会并行执行所有异步任务,自动按原数组顺序收集结果,不用你手动维护counter:
var where_clauses = condition_array; return new Promise(function (resolve, reject) { async.map(where_clauses, function(where_clause, cb) { Model.count(where_clause, function(err, result) { if (err) return cb(err); // 将当前结果传递给async.map cb(null, result); }); }, function(err, results) { if (err) return reject(err); console.log('counter', results); resolve(results); }); });
这个方案的优势是并行执行效率高,所有数据库请求同时发起,不会浪费时间等待前一个完成,而且结果顺序和where_clauses完全一致。
方案2:用async.eachSeries(严格顺序执行)
如果你的业务需要严格按照where_clauses的顺序执行查询(比如前一个查询完成后再发起下一个),可以用async.eachSeries:
var where_clauses = condition_array; var counter = []; return new Promise(function (resolve, reject) { async.eachSeries(where_clauses, function(where_clause, cb) { Model.count(where_clause, function(err, result) { if (err) return cb(err); counter.push(result); // 告诉async当前任务完成,可以执行下一个 cb(null); }); }, function(err) { if (err) return reject(err); console.log('counter', counter); resolve(counter); }); });
这个方案会逐个执行异步任务,确保顺序,但效率比并行低一些,适合有依赖顺序的场景。
方案3:用原生Promise.all(无需依赖async库)
如果你的项目更倾向于原生JS写法,不需要依赖async库,可以把每个Model.count包装成Promise,再用Promise.all等待所有任务完成:
var where_clauses = condition_array; // 把每个查询包装成Promise const countPromises = where_clauses.map(clause => { return new Promise((resolve, reject) => { Model.count(clause, (err, result) => { if (err) reject(err); else resolve(result); }); }); }); // 等待所有Promise完成后返回结果 return Promise.all(countPromises) .then(results => { console.log('counter', results); return results; }) .catch(err => { throw err; });
Promise.all的行为和async.map类似,并行执行所有任务,按原数组顺序返回结果,是现代JS异步编程的标准写法。
内容的提问来源于stack exchange,提问作者Pratik Gadoya

