Ошибка Async.times при развертывании приложения Node.js на героку (повторяющийся цикл)

У меня есть веб-приложение, которое использует JavaScript, jQuery и async.times (среди других компонентов), чтобы получить список исполнителей и песен из API Spotify и вставить их на страницу по порядку. На моем локальном сервере Node.js эта функция работает отлично. Однако при развертывании в Heroku, похоже, произошла ошибка, связанная с асинхронной функцией, потому что она дважды запускает цикл и дважды добавляет список.

Это код, который добавляет данные на страницу:

var counter = 0;
      for (var id in relatedArtists) {
        relatedArtists[counter] = relatedArtists[id];
        delete relatedArtists[id];
        counter++;
      }
async.times(counter, function(n, next) {
  console.log(n);
  console.log(relatedArtists[n].id);
  s.getArtistTopTracks(relatedArtists[n].id, "US", function (err, data2) {
    relatedArtists[n].song = data2.tracks[0].name; 
    relatedArtists[n].uri = data2.tracks[0].uri;
    $('#related-artist').append(
      '<p><strong>' + relatedArtists[n].name + '</strong> -- \"' +
      relatedArtists[n].song + '\"</p>'
    );
    next(null, relatedArtists[n].uri);       
  });
}, 

Развернутая версия находится здесь: http://whatshouldilistentotoday.herokuapp.com/finalproject/.

Heroku говорит, что это не должно быть проблемой с их стороны, потому что они используют ванильную установку Node.js на Ubuntu, но я не могу понять, почему async.times запускается нужное количество раз локально, а не на их сервере.


person Yami Medina    schedule 15.12.2015    source источник
comment
Возможно, вам понадобится добавить больше исходников. Например, как устанавливается счетчик?   -  person Gary    schedule 16.12.2015
comment
@Gary Я отредактировал сообщение, чтобы указать, как устанавливается счетчик.   -  person Yami Medina    schedule 16.12.2015
comment
Ты делаешь странные вещи. Где инициализируется relatedArtists? Это массив или объект?   -  person Bergi    schedule 16.12.2015


Ответы (1)


Вы создаете свойства объекта в цикле, который удаляет все свойства этого объекта.

Это напрашивается на неприятности. Из спецификация:

Если новые свойства добавляются к целевому объекту во время перечисления, не гарантируется, что новые добавленные свойства будут обработаны в активном перечислении.

Так что просто не делайте этого, это полностью зависит от реализации. Я не удивлюсь, если это войдет в бесконечный цикл и повесит ваш сервер.

Просто используйте два отдельных объекта, для вашего собственного здравомыслия. Кроме того, я вообще не вижу причин использовать эти целочисленные свойства counter, просто выберите async.forEachOfSeries вместо этого метода .times.

person Bergi    schedule 16.12.2015
comment
Спасибо, я буду работать над этим и думать об этом дальше. У вас есть идея, почему этот код будет работать на моем локальном сервере, несмотря на его недостатки? Я думаю, что heroku просто более строг в этом отношении. - person Yami Medina; 16.12.2015
comment
Для чего нужны два отдельных объекта? Связанные с ними исполнители и песни с родственными исполнителями? - person Yami Medina; 16.12.2015
comment
@YamiMedina: Возможно, вы используете другую версию узла. Или relatedArtits был инициализирован по-другому каким-то образом (на самом деле причин множество) - person Bergi; 16.12.2015
comment
@YamiMedina: отдельный объект должен быть relatedArtistsByCounter, в отличие от relatedArtists по идентификатору. Вы вообще не должны использовать delete. Или, если вы использовали эту counter штуку только для async.times итераций и не нуждались в ней для чего-то еще (я не знаю?), вы должны просто поменять свой метод перечисления. - person Bergi; 16.12.2015
comment
Благодарю вас! Я создал новый объект с именем relatedArtistsByCounter для хранения и удаления relatedArtists[id] и другой информации в цикле, и теперь он правильно печатает в DOM (по одному разу в правильном порядке). - person Yami Medina; 17.12.2015