Jquery延迟:使用带有承诺数组的过滤器

Jquery延迟:使用带有承诺数组的过滤器,jquery,jquery-deferred,Jquery,Jquery Deferred,我是一个客户端新手,试图将注意力集中在jQuery延迟对象上,尤其是链接上。我有一个承诺对象在其过滤工作中替代另一个承诺对象的情况: // 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":"sec

我是一个客户端新手,试图将注意力集中在jQuery延迟对象上,尤其是链接上。我有一个承诺对象在其过滤工作中替代另一个承诺对象的情况:

// 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() {

但这并不能改变结果

你知道我错过了什么吗

波利

好吧,我对“一系列承诺就是一系列承诺,而不是承诺”的解释显然没有抓住要点。这里有一个更完整的解释

jQuery 1.8+文档中的
Deferred.then()
说明了它的
doneFilter
failFilter
progressFilter
参数:

这些过滤器函数可以返回要传递给的新值 承诺的
.done()
.fail()
回调,或者它们可以返回 另一个可观察到的物体(延迟、承诺等)将通过其 已解决/拒绝承诺回调的状态和值

因此,在jQuery 1.8+中,
.then()
(尤其是链接到它的内容)的行为由返回的内容决定。返回一个可观察的对象(延迟或承诺)与返回任何其他类型的对象有根本的不同

您的两个代码示例在这方面有所不同:

  • 在第一个例子中,
    。然后(function(){…})
    返回一个承诺,因此传递给链的可观察对象就是该承诺
  • 在第二种情况下,
    .then(function(){…})
    返回一个数组,因此沿链传递的可观察对象是一个Promise,其状态与从其左侧馈送
    .then()
    的状态相同(即“已解析”),但具有数组的解析值
如果你能理解上面的第二点,那么你就应该很好地理解为什么你会有你观察到的行为

为了解决这个问题,第二个代码示例需要遵循与第一个相同的总体模式。行
返回第二层延迟。promise()非常重要<代码>arr
可以定义、填充并提交到
$。当()
完全位于
顶层时推迟。然后(function(){…})

var top_layer_deferred=$.deferred();
setTimeout(函数(){
log(“即将解析顶层”);
top_layer_deferred.resolve('top_layer_deferred');
}, 5000);
var top\u layer\u filter=top\u layer\u deferred.promise()。然后(函数(结果){
log('顶层然后结果:'+结果);
var second_layer_deferred=$.deferred();
var-arr=[];

对于(var i=0;i您想做什么?在您当前的示例中,在链接异步操作(一个接一个)时,将延迟添加到数组没有意义,并且只有在同时启动所有异步操作时才会使用数组(因此每个操作都是独立的)我要做的是:(1)启动异步动作a。(2)a完成后,启动独立动作B1,B2..Bn。(3)然后在B1、B2、Bn全部完成后做些什么。我知道有一些方法可以在不使用过滤器的情况下重组代码以实现我的目标,但我很想找出我的过滤器方法不起作用的原因。
$.when.apply(null,top_layer_filter).done( 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');
});