2013-04-07 3 views
1

У меня есть приложение для определения пятен и вы хотите дождаться окончания цикла. Но он работает только после перезагрузки моего приложения.jQuery Отложенное должно работать, но не

function matchRecommendations(result) { 
var deferreds = new Array(); 
for (var i = 0; i < result.length; i++) { 
    // Async wait 
    var dfd = $.Deferred(); 
    deferreds.push(dfd.promise()); 

    ... 

    // Wait for search to finish 
    search.tracks.snapshot(0, 1).done(
      function(snapshot) { 
       // If match was found => create recommendation object 
       var uri = snapshot._uris[0]; 
       var meta = snapshot._meta[0]; 
       if ($.type(meta) !== "undefined") { 
        if ($.type(meta.name) === "string") { 
         console.log(uri); 
         var rec = new Recommendation(uri, meta, 
           explanation, score); 
         RadioView.prototype.addRecommendation(rec); 
        } 
       } 

       // Async task finished 
       dfd.resolve(); 
      }); 
} 

return deferreds; 
} 

Здесь я вызываю метод выше и хочу дождаться его завершения.

$.when.apply($, matchRecommendations(result)).done(
          function() { 
           console.log("finished"); 
           RadioView.prototype.render(); 
          }); 

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

+3

Если 'snapshot()' уже возвращает обещание, то использование 'done()' подразумевало бы, почему вы не возвращаете это обещание вместо создания нового? – adeneo

+0

Уверены, что вы не получаете ошибок js или ошибок ajax в этом процессе? Потому что ваш, когда применяется к этому массиву отложенных, кажется, полностью в порядке. – lib3d

ответ

0

Это действительно старая знакомая проблема с областью, в которой есть только одна область в пределах matchRecommendations(), и все значения, заданные в его цикле for, имеют конечное значение, а другое нет, когда этот цикл завершается.

Существует несколько способов обойти это, простейшее (как вы уже используете jQuery), чтобы перебирать массив result с jQuery.each().

код будет выглядеть следующим образом:

function matchRecommendations(result) { 
    var promises = []; 
    $.each(result, function(i, rslt) { 
     ... 
     var p = search.tracks.snapshot(0, 1).done(function(snapshot) { 
      var uri = snapshot._uris[0]; 
      var meta = snapshot._meta[0]; 
      if ($.type(meta) !== "undefined" && $.type(meta.name) === "string") { 
       console.log(uri); 
       RadioView.prototype.addRecommendation(new Recommendation(uri, meta, explanation, score)); 
      } 
     }); 
     promises.push(p); 
    }); 
    return promises; 
} 

Примечания:

  • Как @adeneo указывает, search.tracks.snapshot() возвращает обещание (по крайней мере, кажется, можно предположить, что делает), так что ненужное создание вторичного Отложенного, которое должно быть разрешено в каскаде.
  • (Doh!) Без дополнительной отсрочки проблема с областью действия фактически исчезает, поэтому вы можете вернуться в цикл for, если хотите.
+0

Все ваши предложения отлично работают;) ... но, как и мой первый подход, не в первый раз. Поэтому я думаю, что отложенный материал не проблема. Должен смотреть на эти замечательные документы в виде предварительного просмотра api ... Во всяком случае, переписал мой метод для использования jquery each, thx! – gausss

+0

Свен, я не могу прокомментировать Spotify, потому что я не человек Spotify, но, похоже, у них есть твердая приверженность документации. Надеюсь, с тобой все будет в порядке. Удачи. –

0

Ваш код, похоже, имеет проблемы с определением области видимости, поэтому, вероятно, только последний отложенный запрос будет разрешен. Я не знаю, как вы проверяете обратный вызов done, но проблема с областью определения может быть причиной ваших проблем (если только result.length не окажется 1).

Вам необходимо создать новую область для каждого отложила:

var deferreds = []; 
for (var i = 0; i < result.length; i++) { 
    (function(dfd) { 
    deferreds.push(dfd.promise()); 
    search.tracks.snapshot(0, 1).done(function(snapshot) { 
     ... 
     dfd.resolve(); 
    }); 
    })($.Deferred()); 
}; 

Если result случается массив, вы можете создать немного более читаемый код:

var deferreds = $.map(result, function() { 
    var dfd = $.Deferred(); 
    search.tracks.snapshot(0, 1).done(...); 
    return dfd.promise(); 
});  
Смежные вопросы