我是一个客户端新手试图围绕jQuery Deferred对象,特别是链接。我有一个promise对象在其过滤工作中替换另一个promise对象的情况:
// works great. output:
// about to resolve top layer
// top layer then results: {"id":"top_layer_deferred"}
// about to resolve second layer item 0
// top layer done: {"id":"second_layer_deferred"}
var top_layer_deferred = $.Deferred();
setTimeout(function() {
console.log('about to resolve top layer');
top_layer_deferred.resolve( { id: 'top_layer_deferred' } )
}, 10000 );
var top_layer_filter = top_layer_deferred.promise().then( function( results ) {
console.log('top layer then results: ' + JSON.stringify(results) );
var second_layer_deferred = $.Deferred();
setTimeout(function() {
console.log('about to resolve second layer item 0');
second_layer_deferred.resolve( { id: 'second_layer_deferred' } )
}, 2000 );
return second_layer_deferred.promise();
});
top_layer_filter.done( function(results) {
console.log('top layer done: ' + JSON.stringify(results) );
});
现在我想做同样的事情,但在过滤器代码中返回一个promise对象数组。 (为了简单起见,我只是在数组上放置一个promise对象而不使用任何参数来解析。)但是过滤器代码过早地触发,好像它没有看到它的参数:
// doesn't work. output:
// about to resolve top layer
// top layer then results: {"id":"top_layer_deferred"}
// top layer done:
// about to resolve second layer item 0
var arr = [];
var top_layer_deferred = $.Deferred();
setTimeout(function() {
console.log('about to resolve top layer');
top_layer_deferred.resolve( { id: 'top_layer_deferred' } )
}, 10000 );
var top_layer_filter = top_layer_deferred.promise().then(function( results ) {
console.log('top layer then results: ' + JSON.stringify(results) );
var second_layer_deferred = $.Deferred();
setTimeout(function() {
console.log('about to resolve second layer item 0');
second_layer_deferred.resolve()
}, 2000 );
arr.push( second_layer_deferred.promise() );
return arr;
});
top_layer_filter.done( function() {
console.log('top layer done: ' );
});
我试过更换线
top_layer_filter.done( function() {
与
$.when.apply(null,top_layer_filter).done( function() {
但这不会改变结果。
关于我缺少什么的任何想法?
波利
答案 0 :(得分:1)
好的,我的解释是“一系列承诺是一个数组,而不是一个承诺”显然没有得到重点。这是一个更完整的解释。
Deferred.then()
的jQuery 1.8+文档说明了doneFilter
,failFilter
和progressFilter
个参数:
这些过滤器函数可以返回要传递的新值 承诺的
.done()
或.fail()
回调,或者他们可以返回 另一个可以通过它的可观察对象(Deferred,Promise等) 解析/拒绝状态和承诺回调的值。
因此,在jQuery 1.8+中,.then()
的行为(尤其是链接到它的任何内容)由返回的内容决定。返回一个可观察对象(Deferred或Promise)与返回任何其他类型的对象根本不同。
您的两个代码示例在这方面有所不同:
.then(function(){...})
返回一个Promise,因此传递给链的可观察对象是Promise。.then(function(){...})
返回一个数组,因此向下传递的可观察对象是一个Promise,其状态与从左边提供.then()
的状态相同(即“已解决” “),但具有数组的已解析值。如果你能掌握上面的第二点,那么你应该很好地了解你为什么会得到你所观察到的行为。
要解决此问题,第二个代码示例需要遵循与第一个相同的整体模式。第return second_layer_deferred.promise();
行至关重要。 arr
可以$.when()
完全定义,填充并提交给top_layer_deferred.then(function(){...})
。
var top_layer_deferred = $.Deferred();
setTimeout(function() {
console.log('about to resolve top layer');
top_layer_deferred.resolve('top_layer_deferred');
}, 5000);
var top_layer_filter = top_layer_deferred.promise().then(function(results) {
console.log('top layer then results: ' + results);
var second_layer_deferred = $.Deferred();
var arr = [];
for(var i=0; i<5; i++) {
arr[i] = $.Deferred();
setTimeout(function(ii) {//Note: double-wrap to form closure, ensuring correct i is reported.
return function() {
if(ii == 99) {//Edit here: try if(ii == 3)
console.log('about to reject second layer item ' + ii);
arr[ii].reject('second layer: ' + ii + ' rejected');
}
else {
console.log('about to resolve second layer item ' + ii);
arr[ii].resolve('second layer: ' + ii + ' resolved');
}
};
}(i), 2000 + i * 2000);
arr[i].done(function(r) {
console.log('second layer : ' + r);
}).fail(function(r) {
console.log('second layer : ' + r);
});
}
//At this point, arr is fully loaded with all the Deferreds it'll ever get,
//so it's safe to apply $.when().
$.when.apply(null, arr).done(function() {
second_layer_deferred.resolve();
}).fail(function(){
second_layer_deferred.reject();
});
return second_layer_deferred.promise();
});
top_layer_filter.done(function() {
console.log('top layer done');
}).fail(function() {
console.log('top layer failed');
});
为了更好的衡量,我已经包含了一种机制,可以使第二级Deferred之一失败(编辑指示的代码)。你会看到