我有一组JSON对象。这个数组在for循环中,并且随着信息从数据库中获得,它会不断地将它们添加到数组中。数组中对象的数量可能与从数据库返回的结果数量不同(因为只有一些位置可能具有用户正在搜索的食物类型)。
例如,我可以在rows
返回12家餐馆,但只有3家卖汉堡包,所以我不能只做if (rows.length - 1 == i)
,因为i
只会去当rows.length - 1
为11时,达到2。
因此匹配返回结果(JSON)在for循环中逐个添加。我永远不会先发制人地知道有多少餐馆出售汉堡,直到所有这些餐馆都添加到阵列中。
我尝试了各种技巧,而我从节点得到的常见错误是"不能多次发送标题。"而且我知道为什么它会给我这个错误。它给了我这个错误,因为循环的每次迭代都会返回它在数组中的任何内容。
输出的一个例子
第一次迭代:
{ "results": [ {"name_of_restaurant": "joes burgers", "open_now": true }] }
第二次迭代:
{ "results": [ {"name_of_restaurant": "joes burgers", "open_now": true }, { "name_of_restaurant": "five guys", "open_now": true }] }
第三次迭代:
{ "results": [ { "name_of_restaurant": "joes burgers", "open_now": true }, "{ name_of_restaurant": "five guys", "open_now": true },
" { name_of_restaurant": "shake shack", "open_now": true }]
}
我想要一种捕获第三次迭代的方法,以便将其发送回客户端。
要明确,我不是在寻找array.length - 1
。我的问题要复杂得多。
编辑 - 已添加代码
function retrieveLocation(callback) {
var locationsWithinVisibleMapRectQuery = "SELECT * FROM locations WHERE Y(coordinates) > " + req.body.SWCoordLat + "AND Y(coordinates) < " + req.body.NECoordLat + "AND X(coordinates) > " + req.body.SWCoordLong + "AND X(coordinates) < " + req.body.NECoordLong + ";";
connection.query(locationsWithinVisibleMapRectQuery, function(err, rows) {
if (err) throw err;
var jsonObject = {
"results" : []
};
//console.log("Number of businesses: " + rows.length);
for(var i = 0; i < rows.length; i++) {
console.log("Business number " + i);
var businessName = rows[i].name;
console.log(businessName);
console.log();
var x = rows[i].coordinates.x;
var y = rows[i].coordinates.y;
getMenuForEachLocation(x, y, businessName, rows, i, function(err, obj) {
if (err) {
callback(err, null);
}
jsonObject["results"].push(obj);
if( jsonObject["results"] == the last index) { // figure a way to get last iteration to send back as a response
callback(null, jsonObject);
}
});
}
});
}
retrieveLocation(function(err, jsonObject) {
if (err) throw err;
res.json(jsonObject);
});
答案 0 :(得分:2)
检查.length
results
数组的.length
等于rows
数组results
的方法的工作示例。请注意,由于i
是异步填充的,因此生成的数组可能不是var rows = [0, 1, 2, 3, 4, 5, 6]
, results = []
, asyncFn = function(n) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(n)
}, Math.random() * 3000)
})
}
, complete = function(callback) {
for (var i = 0; i < rows.length; i++) {
asyncFn(i).then(function(data) {
results.push(data);
console.log(results);
if (results.length === rows.length) callback(rows, results)
})
}
}
complete(
// `callback` : do stuff when `results` `.length` is equal to `rows` `.length`
function(rows_, results_) {
console.log(rows_, results_)
alert("complete");
}
);
的顺序
${testBean.test["hello"]}
答案 1 :(得分:1)
据我所知,getCheckinsForEachLocation()
的回调函数仅在条件满足时触发,因此无法知道何时在回调函数内处理所有数据。
我们目前知道rows.length
有多少行,而我们需要知道的是当所有getCheckinsForEachLocation()
被触发时,我们需要另一个索引和oncomplete
回调。
这是一个有效的例子:
var globalIndex;
// Pseudo async function
function getCheckinsForEachLocation (rows, i, callback, oncomplete) {
setTimeout(function () {
if (-1 != rows[i].indexOf('burgers')) {
callback(null, rows[i]);
}
// Add up the times that the function was called to
// find out if they have called all.
if (++globalIndex == rows.length) {
oncomplete();
}
}, Math.random() * 3000);
}
function retrieveLocation(callback) {
// Pseudo data retrived from database
var rows = ["sandwich", "burgers 1", "salad", "burgers 2", "sushi", "burgers 3", "tea"];
var jsonObject = {
"results" : []
};
// Reset the time that `getCheckinsForEachLocation` was called
globalIndex = 0;
for (var i = 0, rowsLength = rows.length; i < rowsLength; ++i) {
console.log("Business number " + i);
getCheckinsForEachLocation(rows, i, function(err, obj) {
if (err) {
callback(err, null);
}
jsonObject["results"].push(obj);
}, function () {
callback(null, jsonObject);
});
}
}
retrieveLocation(function(err, jsonObject) {
if (err) throw err;
alert(JSON.stringify(jsonObject));
});
答案 2 :(得分:1)
我之前提到了承诺 - 这可能适合您的需求。我绝对建议您查看有关承诺的更多信息。快速注意,这都是es6 - 所以不要过于束缚w / arrow函数语法等。如果你正在运行node 4.0&gt; =那么这应该是开箱即用的;
function retrieveLocation() {
const locationsWithinVisibleMapRectQuery = "SELECT * FROM locations WHERE Y(coordinates) > " + req.body.SWCoordLat + "AND Y(coordinates) < " + req.body.NECoordLat + "AND X(coordinates) > " + req.body.SWCoordLong + "AND X(coordinates) < " + req.body.NECoordLong + ";";
return new Promise((resolve, reject) => {
connection.query(locationsWithinVisibleMapRectQuery, (err, rows) => {
if (err) reject(err);
resolve(rows);
});
})
.then(rows => {
return Promise.all(rows.map(row => {
const businessName = row.name;
const x = row.coordinates.x;
const y = row.coordinates.y;
return new Promise((resolve, reject) => {
getCheckinsForEachLocation(x, y, businessName, rows, i, (err, result) => {
if (err) reject (err);
resolve(result);
})
})
.then(result => result)
.catch(err => {
throw new Error(err)
});
}));
})
.then(result => result[result.length - 1]);
}
retrieveLocation()
.then(jsonObject => res.json(jsonObject))
.catch(err => console.log(err));