2015-06-17 3 views
0

Я пишу код, который итерации сначала через массив, а затем итерации через массив, содержащийся в исходном массиве.Лучший шаблон для доступа к вложенным данным в Javascript

Я заканчиваю этот странный образец, который я повторяю, и я уверен, что он не оптимизирован. Итерируя через последний элемент массива rssFeeds, он изменяет значение «triggerCallback» на true. Позже, повторяя массив элементов, условная проверка, если оба triggerCallback истинны, и массив элементов выполняет итерацию через свой последний элемент, после чего он вызывает обратный вызов, который будет использоваться в шаблоне водопада 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 различных элементов. ЭлементыToPost.

[ 
    { 
    "_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": "14344896", 
    "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" 
     } 
     } 
    ] 
    } 
] 
+0

Я использую async в настоящий момент для картины водопада. Вы знаете, какой метод примерно охватывает эту функциональность? Мне просто нужно погрузиться и посмотреть, что я могу найти – Antoine

+0

Подождите .. это не асинхронные циклы? Это нелепо. Вы должны включить '.forEach'' в циклы for, чтобы вы могли выйти из функции, как только вы вызываете обратный вызов. –

+0

@PatrickRoberts Я не уверен, что библиотека относится к этой ситуации. Похоже, он синхронно свертывается в вложенные данные.Просто его функция countSuccessPosts называется асинхронно. По крайней мере, так я читаю. Это помогло бы, если бы у нас были образцы данных. –

ответ

0

Вам не нужно отслеживать последний элемент. Просто вызовите обратный вызов после выхода обоих циклов. Я также изменил .forEach на циклы, поскольку они выполняются быстрее.

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

Конечно, если вы не хотите позвонить countSuccessPosts без обратного вызова вызывающий код может выглядеть следующим образом:

var successPosts = countSuccessPosts(rssFeeds); 

И вы можете переформатировать функцию, чтобы выглядеть следующим образом:

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; 
} 
+0

A) Нет необходимости использовать обратный вызов, когда «rssFeeds» можно получить синхронно. B) В противном случае, если '// некоторый код' имеет асинхронные вызовы, ваш код все равно сломается, потому что' cb' вызывается до завершения функции async. – naomik

+1

@naomik возможно, что он использует async просто потому, что синтаксис помогает организовать и упростить его уже пирамидоподобный код. –

+0

Ну, плохо писать асинхронный контроль вокруг синхронного кода. Не поощряйте это. JavaScript однопоточный. Добавление «обратного вызова» к вашей функции не меняет этого. – naomik

2

Я не проверял это, но он очень похож на то, что я использую в своем проекте:

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

Как уже упоминалось, вам это нужно, только если у вас есть активные вызовы методов асинхронного вызова внутри внутреннего цикла.

+0

Извините, но вы немного опоздали. '// какой-то код' не был асинхронным. –

+1

ой, это потому, что я потратил много времени, чтобы отменить ответ, LOL. –

+0

Не волнуйся, так получилось. –

0

Подождите, почему вы используете обратный вызов, когда вы можете читать данные синхронно?

После того как вы обновили свой вопрос, это выглядит, как вы просто суммирование числа элементов в массиве

Вот полностью синхронная версия, которая подсчитывает количество itemsToPost, которые имеют действительный response.id набор.

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, потому что все, что бывает внутри эта функция есть синхронный.

+0

Уверенный код короче, но он работает медленнее, чем мое решение, и его труднее читать. –

+1

Причина в том, что я разделяю функциональность на небольшие методы, многие из которых полагаются на асинхронные вызовы (вызовы базы данных и сетевых API) и организуют код, используя шаблон асинхронного водопада и проходящий через массив rssFeeds. – Antoine

+0

@mrmayfield удачи вам и вашему асинхронному фасаду. – naomik