我试图找出一种方法来等待多个延迟对象并在完成后处理它们,可能就像为延迟对象启动下一组.
我被困了,因为下面的结果不是预期的结果.
我期待结果为
allDone resovled values are 1,2,3
实际结果是
allDone resovled values are 1,2
var dfd1 = new $.Deferred(); var dfd2 = new $.Deferred(); var dfd3 = new $.Deferred(); var dfds = [ dfd1,dfd2,dfd3 ]; var resolvedValues = []; $.when.apply($,dfds).done(function() { dfds.forEach(function(dfd){ console.log("inloop"); dfd.promise().done(function(value) { resolvedValues.push(value); }); }); console.log("allDone resovled values are" + resolvedValues); }) dfd1.resolve(1); dfd2.resolve(2); dfd3.resolve(3);
解决方法
为什么,见下文.但是你过度复杂了. :-)你给出最终承诺的回调给你解决的值作为参数:
$.when.apply($,dfds).done(function(a,b,c) { // Here,a is 1,b is 2,c is 3 // Or you can access them on `arguments` })
实例:
var dfd1 = new $.Deferred(); var dfd2 = new $.Deferred(); var dfd3 = new $.Deferred(); var dfds = [ dfd1,dfds).done(function() { // Use a trick to turn `arguments` into a real array var a = Array.prototype.slice.call(arguments); // Show what we got snippet.log("allDone: " + a.join(",")); }) dfd1.resolve(1); dfd2.resolve(2); dfd3.resolve(3);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <!-- Script provides the `snippet` object,see http://Meta.stackexchange.com/a/242144/134069 --> <script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
旁注:我假设你故意处理一个数组.如果您需要等待固定数量的承诺,只需使用更简单的表单即可
$.when(dfd1,dfd3).then(function(a,c) { // ... });
这就是为什么你得到你得到的非常奇怪的结果:jQuery的Deferred / Promise对象有一个问题,即它们是混乱的:当你对它们调用done时,你不知道你的回调是同步执行还是异步执行.这是一个严重的缺陷,而且真正的Promises / A实现没有(回调总是异步的).
如果诺言尚未解决,jQuery将异步调用回调.但如果没有解决它会同步调用它:
var d1 = $.Deferred(); d1.done(function() { console.log("I'm called asynchronously"); }); d1.resolve(); var d2 = $.Deferred(); d2.resolve(); d2.done(function() { console.log("I'm called synchronously"); });
所以你的代码中发生的事情就是整个完成的回调,当在最后一个被解析的promise(dfd3)的完成回调期间触发了.由于承诺在完成完成回调之后才被标记为已解决,因此当代码运行时,dfd1和dfd2将被解析,但dfd3仍在处理中.所以你的内部回调是为dfd1和dfd2同步调用的,但对dfd3是异步的.因此,在将dfd3返回值推送到阵列之前,您将输出结果.