$ .when.apply在Array of Promises上

时间:2014-02-02 20:15:54

标签: javascript jquery ajax promise deferred

我搜索了许多非常相似的问题。我找到了一个几乎完全正在寻找的东西,除了它没有任何错误处理,并且在尝试实现错误处理时我遇到了一些问题。

我的目标是创建一个接收名称数组的函数,在循环中创建$ .ajax请求,将返回promise对象推送到一个数组中,然后我将其提供给$ .when.apply($,arrayOfPromises)。然后(//等解析一个延迟的主数据,其中arrayOfPromises中的所有promise都已被解析。最终结果是创建一个从ajax调用返回的数据数组。

到目前为止我有这个:http://jsfiddle.net/BGx2h/1/

这几乎就是我的需要。如果数组包含指向所有有效资源的指针,那么一切似乎都按预期工作。但是,如果有一个资源的调用不存在(例如我的小提琴中的/test/doesnt.exist.txt),那么“didnt.exist”的ajax调用在任何其他调用之前完成,即master延迟(connectiondfd)在其他调用有机会完成之前得到解决(您可能需要多次运行小提琴才能获得此结果)。这是我目前的功能:

function multiAsync() {
    var i,data=[],connections=[],
        targets=['John.Smith','Jane.Doe','Bob.Someone','doesnt.exist'];

    var connectiondfd = $.Deferred();

    for(i=0;i<targets.length;i++) {
        connections.push($.ajax({
            url:'http://porticium.ca/test/'+targets[i]+'.txt',
            type:'GET',
            async:true,
            timeout:5000
        }).then(function(newData) {
            data.push(newData);
        },function() {
            data.push("NO DATA");
        }));
}

    $.when.apply($,connections)
        .then(
            function() { connectiondfd.resolve(); },
            function() { connectiondfd.resolve(); }
        );


    $.when(connectiondfd).done(function() {
        alert("FINAL: " + data);
    });
}

肯定会欣赏这方面的一些帮助,它一直让我疯狂!

谢谢, 罗布

2 个答案:

答案 0 :(得分:2)

所以我更多地玩这个并研究我接受的答案中提供的功能(再次感谢!)我设法找到另一个使用适合我目的的延迟解决方案。

我创建了一个名为whenAll的函数,它接受一个promises数组,创建一个延迟的master,并将完成和失败的回调添加到推送返回数据的每个promise,或者将错误消息添加到数组中然后检查长度数据数组与提供的promises数组的长度之间的关系,解析时它们是相同的。

这是:

function whenAll(promises) {
    var i,data=[],dfd=$.Deferred();
    for(i=0;i<promises.length;i++) {
        promises[i].done(function(newData) {
            data.push(newData);
            if(data.length==promises.length) {
                dfd.resolve(data);
            }
        }).fail(function() {
            data.push("NO DATA");
            if(data.length==promises.length) {
                dfd.resolve(data);
            }            
        });
    }
    return dfd.promise();
}

答案 1 :(得分:0)

如果你的一个promisses失败,$.Deferred.when函数会立即触发,你可以创建一个'wrapper'延迟处理一系列promisses并在它们进来时调度它们然后激活master的自己的处理程序完成,即使有些失败,有些成功。这个特殊的功能只是从我拥有的通用工具文件中复制而来,为了简洁起见使用Underscore,但基本模式就是你所需要的:

    function completed( firstParam ) {

        var args = _.toArray( arguments ),
            i = 0,
            length = args.length,
            pValues = new Array( length ),
            count = length,
            deferred = length <= 1 && firstParam && $.isFunction( firstParam.promise ) ? firstParam : $.Deferred(),
            promise = deferred.promise(),
            state = 'resolved';

        function alwaysFunc( i ) {

            return function ( value ) {

                args[ i ] = arguments.length > 1 ? _.toArray( arguments ) : value;
                state = ( this.state && this.state() === 'rejected' ) ? 'rejected' : state;
                if ( !( --count ) ) deferred[ ( state === 'rejected' ? 'reject' : 'resolve' ) + 'With' ]( deferred, args );

            };

        }

        function progressFunc( i ) {

            return function ( value ) {

                pValues[ i ] = arguments.length > 1 ? _.toArray( arguments ) : value;
                deferred.notifyWith( promise, pValues );

            };

        }

        if ( length > 1 ) {

            for ( ; i < length; i++ ) {

                if ( args[ i ] && args[ i ].promise && $.isFunction( args[ i ].promise ) )
                    args[ i ].promise().always( alwaysFunc( i ) ).progress( progressFunc( i ) );

                else --count;

            }

            if ( !count ) deferred.resolveWith( deferred, args );

        } else if ( deferred !== firstParam ) deferred.resolveWith( deferred, length ? [ firstParam ] : [] );

        return promise;

    }

无论如何,您像往常一样创建并附加处理程序到各个请求/ promisses,然后通过apply通过此函数传递它们。每个请求的状态都是单独处理的,并且该函数会跟踪仍有多少未解析的状态。一旦解决了所有问题,它就会根据集合触发自己的解决方案。即使一个或所有组件promisses失败,所有仍然执行,并且主延迟等待直到它们全部解决。在初始调用之后它不会处理添加进一步的promisses / deferreds - 创建你需要的所有,然后将它们传递给这个函数。

我不能赞同这个剧本:它是通过一个同事“传递给我” - 我认为是从其他地方获得的,但是世界上最差的人在代码中保留评论/归属。如果有人认出代码并且可以指向我的作者...