jQuery Deferred 应该可以工作,但不能
Posted
技术标签:
【中文标题】jQuery Deferred 应该可以工作,但不能【英文标题】:jQuery Deferred should work but doesn't 【发布时间】:2013-03-29 15:26:17 【问题描述】:我有一个 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();
);
我看不出为什么这个灵魂不起作用的问题。问题是第一次加载时没有执行“完成”回调。如果我重新加载应用程序,它工作得很好 ...延迟的东西有什么问题吗?
【问题讨论】:
如果snapshot()
已经返回了一个promise,done()
的使用意味着,你为什么不只是返回那个promise 而不是创建一个新的?
确定过程中没有出现js错误或者ajax错误?因为你的 when 应用于这个 deferreds 数组似乎完全没问题。
【参考方案1】:
这确实是一个老生常谈的范围问题,matchRecommendations()
中只有一个范围,并且在其for
循环中设置的所有变量都有其最终值,而当该循环退出时没有其他值。
有很多方法可以解决这个问题,最简单的(因为您已经在使用 jQuery)是使用 jQuery.each()
循环遍历 result
数组。
代码如下所示:
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()
返回一个承诺(至少可以安全地假设它确实如此),因此无需创建二级 Deferred 以在级联中解决。
(Doh!)如果没有第二个 Deferred,范围问题实际上会消失,因此您可以根据需要返回到 for
循环。
【讨论】:
您的所有建议都可以正常工作;)...但就像我的第一种方法一样,不是第一次。所以我想延迟的东西毕竟不是问题。必须查看 spotify preview api 的那些很棒的文档...无论如何都重写了我的方法来使用每个 jquery,谢谢! Sven,我不能对 Spotify 发表评论,因为我不是 Spotify 人,但他们似乎对文档有着坚定的承诺。希望你会没事的。祝你好运。【参考方案2】:您的代码似乎存在范围问题,这就是为什么可能只有最后一个 deferred 会得到解决的原因。我不知道您如何检查正在执行的 done
回调(未执行),但范围问题可能会导致您的问题(除非 result.length
恰好是 1)。
您需要为每个 deferred 创建一个新范围:
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();
);
【讨论】:
以上是关于jQuery Deferred 应该可以工作,但不能的主要内容,如果未能解决你的问题,请参考以下文章
有人可以清楚地解释 jQuery.when() 和 deferred.then() 的工作原理吗?
jQuery Deferred/promise 没有按预期工作
jQuery异步框架探究2:jQuery.Deferred方法
通过 ES6 Promise 和 jQuery Deferred 的异同学习 Promise