1

我有一个 Spotify 应用程序,想等待一个循环完成。但它只在重新加载我的应用程序一次后才有效。

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

我看不出为什么这不起作用的问题。问题是第一次加载时没有执行“完成”回调。如果我重新加载应用程序,它就可以正常工作......延迟的东西有什么问题吗?

4

2 回答 2

0

您的代码似乎存在范围问题,这就是为什么可能只有最后一个 deferred 会得到解决的原因。我不知道您如何检查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();
});    
于 2013-04-07T17:27:38.080 回答
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()返回一个promise(至少假设它似乎是安全的),所以没有必要创建一个二级Deferred 以级联方式解决。
  • (Doh!)如果没有辅助 Deferred,范围问题实际上会消失,因此如果您愿意,可以返回for循环。
于 2013-04-08T00:36:11.793 回答