在Javascript中访问嵌套数据的更好模式

在Javascript中访问嵌套数据的更好模式,javascript,arrays,node.js,Javascript,Arrays,Node.js,我正在编写一些代码,首先遍历数组,然后进一步遍历原始数组中包含的数组 我最终得到了这个奇怪的模式,我重复着这个模式,我确信它没有得到优化。在遍历最后一个rssFeeds数组项时,它将“triggerCallback”的值更改为true。稍后,在迭代项数组时,条件检查triggerCallback是否为true,以及items数组是否正在迭代其最后一个项,此时它将触发一个回调以在async.js的瀑布模式中使用 function countSuccessPosts(rssFeeds, cb){

我正在编写一些代码,首先遍历数组,然后进一步遍历原始数组中包含的数组

我最终得到了这个奇怪的模式,我重复着这个模式,我确信它没有得到优化。在遍历最后一个rssFeeds数组项时,它将“triggerCallback”的值更改为true。稍后,在迭代项数组时,条件检查triggerCallback是否为true,以及items数组是否正在迭代其最后一个项,此时它将触发一个回调以在async.js的瀑布模式中使用

function countSuccessPosts(rssFeeds, cb){
  var successCounter = 0;

  var triggerCallback = ''

  rssFeeds.forEach(function(feed, index, array){
    if(index == array.length - 1){
      triggerCallback = 'true'
    }

    feed.itemsToPost.forEach(function(item, itemIndex, itemArray){
      if(item.response.id){
         ++successCounter

      }

      if(itemIndex == itemArray.length - 1 && triggerCallback == 'true'){
        cb(null, rssFeeds, successCounter)
      }
    })
  })

}
构建此模式的最佳方式是什么

数据结构:RssFeeds最多有5个不同的itemsToPost元素

[
  {
    "_id": "55808127b8f552c8157f74a7",
    "name": "",
    "imageUrl": "",
    "url": "http://www.taxheaven.gr/bibliothiki/soft/xml/soft_law.xml",
    "latestDate": "1434056400000",
    "endpoints": [
      {
        "_id": "554f9319bc479deb1757bd2e",
        "name": "Wise Individ",
        "id": 26413291125,
        "type": "Group",
        "__v": 0
      }
    ],
    "__v": 1,
    "itemsToPost": [
      {
        "title": "Aριθμ.: Υ194/12.6.2015 Τροποποίηση απόφασης ανάθεσης αρμοδιοτήτων στον Αναπληρωτή Υπουργό Οικονομικών Δημήτριο Μάρδα.",
        "summary": "Τροποποίηση απόφασης ανάθεσης αρμοδιοτήτων στον Αναπληρωτή Υπουργό Οικονομικών Δημήτριο Μάρδα.",
        "url": "http://www.taxheaven.gr/laws/circular/view/id/21113",
        "published_at": 1434056400000,
        "time_ago": "5 days ago",
        "guid": {
          "link": "http://www.taxheaven.gr/laws/circular/view/id/21113",
          "isPermaLink": "true"
        }
      }
    ]
  },
  {
    "_id": "558093013106203517f96d9c",
    "name": "",
    "imageUrl": "",
    "url": "http://www.taxheaven.gr/bibliothiki/soft/xml/soft_new.xml",
    "latestDate": "1434489601236",
    "endpoints": [],
    "__v": 0,
    "itemsToPost": [
      {
        "title": "Taxheaven - Άμεση ενημέρωση - Έγκαιρη επιστημονική κωδικοποίηση - Καινοτομικά εργαλεία. Κωδικοποιήθηκαν όλοι οι νόμοι στους οποίους επιφέρει αλλαγές ο νόμος 4330/2015",
        "summary": {},
        "url": "http://www.taxheaven.gr/news/news/view/id/24088",
        "published_at": 1434494400000,
        "time_ago": "about 4 hours ago",
        "guid": {
          "link": "http://www.taxheaven.gr/news/news/view/id/24088",
          "isPermaLink": "true"
        }
      }
    ]
  }
]

您不需要跟踪最后一项。只要在两个循环退出后调用回调函数。我还将
.forEach
更改为for循环,因为这些循环执行得更快

function countSuccessPosts(rssFeeds, cb) {
  var index, itemIndex, feed, item;

  for (index = 0; index < rssFeeds.length; index++) {
    feed = rssFeeds[index];

    for (itemIndex = 0; itemIndex < feed.itemsToPost.length; itemIndex++) {
      item = feed.itemsToPost[itemIndex];

      if(item.response && item.response.id) {
        successCounter++;
      }
    }
  }

  cb(null, rssFeeds, successCounter);
}
您可以将函数重新格式化为如下所示:

function countSuccessPosts(rssFeeds) {
  var index, itemIndex, feed, item, successCounter = 0;

  for (index = 0; index < rssFeeds.length; index++) {
    feed = rssFeeds[index];

    for (itemIndex = 0; itemIndex < feed.itemsToPost.length; itemIndex++) {
      item = feed.itemsToPost[itemIndex];

      if(item.response && item.response.id) {
        successCounter++;
      }
    }
  }

  return successCounter;
}
函数countSuccessPosts(rssFeeds){
var索引,itemIndex,提要,item,successCounter=0;
对于(索引=0;索引
我没有检查这一点,但它与我目前在项目中使用的非常相似:

function countSuccessPosts(rssFeeds, cb){
  async.each(rssFeeds, function(eachFeed, outerCallback) {
     async(eachFeed.itemToPost, function(eachItem, innerCallback) {
        if(item.response.id) {
            //Do Something That Is Actually Async. Could be asking the server for success flag, for instance.
            doSomethingThatIsActuallyAsync(item.response.id).then(function (err) {
                if (!err) {
                    successCounter = successCounter + 1;
                }
                innerCallback();
            });
        } else { //This could be to skip "empty responses" without the need to go to the server, right?
            innerCallback();
        }
     }, outerCallback);
  }, function() {
      //All done
      cb(null, rssFeeds, successCounter);
  }); 
}

正如其他人所提到的,只有在内部循环中有实际的异步方法调用时,才需要它。

等等,既然可以同步读取数据,为什么还要使用回调

在你更新了你的问题之后,看起来你只是在总结一个问题 数组中的元素数

下面是一个完全同步的版本,它统计具有有效
响应.id
集的
itemsToPost
的数量

function countSuccessPosts(rssFeeds) {
  return rssFeeds.reduce(function(sum, x) {
    return sum + x.itemsToPost.filter(function(y) {
      return !!y.response.id;
    }).length;
  }, 0);
}
如果需要将其注入异步控制流,则可以轻松地在其上放置包装器

function(rssFeeds, done) {
  done(null, rssFeeds, countSuccessPosts(rssFeeds));
}


关键是,
countSuccessPosts
有一个同步API,因为在该函数中发生的一切都是同步的。

我现在使用异步作为瀑布模式。您知道哪种方法大致涵盖此功能吗?我可能得潜进去看看能找到什么。。这些不是异步循环吗?那太可笑了。您应该将
.forEach
转换为for循环,以便在调用回调函数时立即退出该函数。@PatrickRoberts我不确定库是否适用于这种情况。看起来他正在同步地向下钻取嵌套数据。只是他的
countSuccessPosts
函数被异步调用。至少我是这样读的。如果我们有一些示例数据会有所帮助。是的,唯一的异步调用是瀑布中的countSuccessPosts,我基本上只是在这里钻取嵌套数据,我只需要经常重复这个模式,想象有一个更优化的路线可以走。你能不能为这个问题提供一个
JSON.stringify(rssFeeds,null,2)
,或者至少是它的一部分,以帮助澄清对象的格式?a)当可以同步访问
rssFeeds
时,不需要使用回调。B) 否则,如果
//某些代码
具有异步调用,那么您的代码无论如何都会中断,因为
cb
在异步函数完成之前被调用。@naomik可能只是因为语法有助于组织和简化他已经像金字塔一样的代码。围绕同步代码编写异步控制是不好的。不要鼓励这样做。JavaScript是单线程的。向函数中添加
回调
不会改变这一点。是的,基本上就是这样。我只是在寻找一种更好的模式来循环这些数据,因为我必须经常这样做,当我通过瀑布模式传递此数组并对其进行变异时。@Mayfield先生,我添加了一个快速编辑,以确保
item.response.id
item.response
未定义时不会抛出引用错误。很抱歉,您迟到了一点
//有些代码
不是异步的。哎哟,那是因为我花了很多时间来修饰答案,哈哈。别担心,这会发生的。@PatrickRoberts至少他添加了一个附言,说只有在内部循环中有异步方法的情况下才有必要这样做。当然,你的代码比较短,但它比我的解决方案运行得慢,原因是我正在将功能分解为一些小方法,其中许多方法依赖于异步(数据库和网络API调用),并使用异步瀑布模式组织代码并通过rssFeeds数组。嘿,我只是想学习一下。如果我的设计没有得到优化,我一点也不会怀疑。如果您对如何更好地组织我的代码有什么建议,请给出我在上面对我的需求的解释,我很乐意听到@mrmayfield我提供了在瀑布控制代码中使用的同步函数和异步包装器。想想看:仅仅因为你在计算代码异步部分的帖子数量,并不意味着这个数量是异步的。如果要在代码的不同部分调用count函数,会发生什么?使用仅异步的api,它似乎有点崩溃,因为它强制回调,即使它是完全同步的。将函数意图与控制流分开,并在必要时使用包装器。是的,这是一个很好的观点。我明白你的意思,一定会留意我的纯同步方法,并尝试将它们排除在异步工作流之外。谢谢你的帮助!
function(rssFeeds, done) {
  done(null, rssFeeds, countSuccessPosts(rssFeeds));
}