【问题标题】:How to get the last index in a JSON array when you don't know how large the array is going to be?当您不知道数组有多大时,如何获取 JSON 数组中的最后一个索引?
【发布时间】:2016-06-10 09:45:09
【问题描述】:

我有一个 JSON 对象数组。这个数组在一个 for 循环中,当信息从数据库中可用时,它会不断地将它们添加到数组中。数组中的对象数量可能与从数据库返回的结果数量不同(因为只有某些位置可能具有用户正在搜索的食物类型)。

例如,我可以在rows 中返回 12 家餐厅,但只有 3 家卖汉堡,所以我不能简单地做if (rows.length - 1 == i),因为i 只会达到 2 而rows.length - 1 是 11 .

所以匹配的返回结果(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);
});

【问题讨论】:

  • 为什么在包含 for 循环完成迭代之前返回结果?我们能看到构建这个数组的代码吗?
  • “我想要一种捕获第三次迭代的方法” 是否要求只在第三次迭代时执行一个过程?
  • 我发布了我的代码给你看。
  • getCheckinsForEachLocation 是异步的吗?
  • 你不能选择使用 Promise 吗?真的会在这里为您尝试做的事情提供帮助。

标签: javascript json node.js for-loop


【解决方案1】:

检查.lengthresults 数组是否等于.lengthrows 数组的方法的工作示例。注意,由于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");
  }
);

【讨论】:

    【解决方案2】:

    据我了解,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));
    });

    【讨论】:

      【解决方案3】:

      我之前提到过承诺 - 这可能会满足您的需求。我绝对建议您查看有关承诺的更多信息。快速注意,这都是 es6 - 所以不要太拘泥于箭头函数语法等。如果你运行的是 node 4.0 >= 那么这应该是开箱即用的;

      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));
      

      【讨论】:

        猜你喜欢
        • 2016-02-16
        • 2020-06-14
        • 2014-09-27
        • 2013-04-25
        • 1970-01-01
        • 1970-01-01
        • 2021-12-03
        • 2023-01-19
        • 2018-12-09
        相关资源
        最近更新 更多