Бесконечный цикл в $(document).ready при взаимодействии с API

Я использую CodePen в этом проекте, и именно так я обнаружил, что в моем коде есть бесконечный цикл. Кроме того, он оценивает номер строки бесконечного цикла как строку 0, поэтому я подозреваю, что это как-то связано с $(document).ready() кусок кода.

Я новичок в jQuery / API, поэтому прошу прощения, если это очевидно.

Вот код:

$(document).ready(function() {
  var key = '*****************';
  var i = 0;
  var hotArray = [];

  function isInArray(value, array) {
    return array.indexOf(value) > -1;
  }

  function getMusic() {
    $.getJSON('http://developer.echonest.com/api/v4/song/search?api_key=' + key + '&artist=led+zeppelin&sort=song_hotttnesss-desc&results=50&bucket=song_hotttnesss', function(data) {
      while ($('.songs li').length < 10) {
        if (!(isInArray(data.response['songs'][i]['hotttnesss'], hotArray))) {
          $('.songs').append('<li>' + data.response['songs'][i]['title'] + '</li>');
          hotArray.push(data.response['songs'][i]['hotttnesss'])
        }
      }
      i++;
    });
  };

  $('.click').click(getMusic);
});

Краткое объяснение кода:

Я пытаюсь получить топ-10 песен Led Zeppelin, когда нажимаю на определенный кусочек страницы (позже, чтобы перейти к исполнителю, введенному пользователем). Но, как работает API Echo Nest, возвращается множество дубликатов. Например, "Лестница на небеса" и "Лестница на небеса" считаются двумя отдельными песнями.

Чтобы обойти эту проблему, я использую значение "hotttnesss" каждой песни, которое уникально для каждой песни. Единственный способ, которым две песни одного исполнителя могут иметь одинаковую горячую текстуру, - это если они на самом деле одна и та же песня, как в случае с этими дубликатами.

Итак, я перебираю каждую из возвращенных песен, пока число сообщаемых песен меньше 10, и сообщаю о песне, если ее значение hotttnesss не входит в массив значений hotttnesss уже сообщенных песен. После сообщения о песне значение hotttnesss песни добавляется в массив.

1 ответ

Решение

i++; должен быть внутри while цикл, а не после него. Вам также нужно установить i в 0 в вашем обратном вызове Ajax, и ограничить этот же цикл до i < data.response['songs'].length,

Например:

function getMusic() {
    $.getJSON('http://developer.echonest.com/api/v4/song/search?api_key=' + key + '&artist=led+zeppelin&sort=song_hotttnesss-desc&results=50&bucket=song_hotttnesss', function(data) {
        var i, songs = data.response['songs'];
        for (i = 0; $('.songs li').length < 10 && i < songs.length; ++i) {
            if (!(isInArray(songs[i]['hotttnesss'], hotArray))) {
                $('.songs').append('<li>' + songs[i]['title'] + '</li>');
                hotArray.push(songs[i]['hotttnesss'])
            }
        }
    });
}

или я бы просто использовал Array#forEach (вы можете использовать его, если вам нужна поддержка IE8):

function getMusic() {
    $.getJSON('http://developer.echonest.com/api/v4/song/search?api_key=' + key + '&artist=led+zeppelin&sort=song_hotttnesss-desc&results=50&bucket=song_hotttnesss', function(data) {
        data.response['songs'].forEach(function(song) {
            if (!(isInArray(song['hotttnesss'], hotArray))) {
                $('.songs').append('<li>' + song['title'] + '</li>');
                hotArray.push(song['hotttnesss'])
            }
        });
    });
}

Примечания стороны:

  1. Объявления функций (например, ваш getMusic) не являются утверждениями, вам не нужен терминатор операторов (;) после них. (Вы делаете после выражения функции, скажем, часть назначения.)

  2. song['hotttnesss'] можно написать song.hotttness, response['songs'] как response.songs и т. д. Если имя свойства не начинается с цифры или не содержит символ, который недопустим в именах идентификаторов JavaScript, нет необходимости указывать его в кавычках.

  3. Там нет цели служить () вокруг вызова функции в большинстве случаев, так

    if (!(isInArray(song['hotttnesss'], hotArray))) {
    

    может быть более четко

    if (!isInArray(song['hotttnesss'], hotArray)) {
    

    (Единственные случаи, когда у них есть цель, включают выражения, вызванные встроенными функциями.)

  4. Вам не нужно ваше isInArray функция; У jQuery уже есть один: $.inArray, (Стоит потратить время на изучение API jQuery, начиная с конца и до конца. Буквально через час или два вы найдете все виды полезных вещей, о которых вы, возможно, не знаете.)

Другие вопросы по тегам