【问题标题】:Execute a set of work in a loop only after the previous set has completed只有在上一组工作完成后才循环执行一组工作
【发布时间】:2012-01-28 04:38:21
【问题描述】:

我有一些代码可以在链中完成一组不同的操作。这组操作本身是在循环中执行的。由于我正在处理的系统的性质,操作集需要同步执行(即下一组操作在第一组完成之前无法执行)。异步执行会抛出远程处理器(不在我的控制范围内),并导致代码失败。现在,我能够让它工作的唯一方法是使用警报框,这真的很蹩脚,不是一个选择。我试过了:

  • 使用 $.ajax,并将异步设置为 false
  • 使用睡眠功能
  • 警报框(在绝望中使用)

这是代码 - 有什么想法吗?:

$('input:checked').each(function(index){                        

    //get the item's location id
    var currentInput = $(this).val();

    var copyUser = function(){$.get(urlCopyPrefix + currentInput + urlSuffix);}
    var moveUser = function(){$.get(urlMovePrefix + moveLocation + urlSuffix);}

    var cleanup = function(){

        var newSibling = $('#module-' + moveLocation);
        newSibling.before('<li>New Line</li>');

        alert('done');
    }

    /* --> THIS IS THE CODE IN QUESTION <-- */
    $.when(copyUser()).pipe(moveUser).then(cleanup);

});

【问题讨论】:

    标签: jquery synchronous jquery-chaining


    【解决方案1】:

    你必须从你的函数中返回 jqXHR 对象:

    var copyUser = function(){
            return $.get(urlCopyPrefix + currentInput + urlSuffix);
        },
        moveUser = function(){
            return $.get(urlMovePrefix + moveLocation + urlSuffix);
        };
    

    那么你可以这样做:

    $.when( copyUser() ).pipe( moveUser ).then( cleanup );
    

    如果您想等待循环中的每个项目在下一个开始之前完成,请使用:

    var $items = $('input:checked'),
        length = $items.length,
        copyUser = function(currentInput)
        {
            return $.get(urlCopyPrefix + currentInput + urlSuffix);
        },
        moveUser = function()
        {
            return $.get(urlMovePrefix + moveLocation + urlSuffix);
        },
        cleanup = function()
        {
            $('#module-' + moveLocation).before('<li>New Line</li>');
        };
    
    function processUser(i)
    {
        $.when( copyUser($items.eq(i).val()) ).pipe( moveUser ).then(function()
        {
            cleanup();
            i < length && processUser(++i);
        });
    }
    
    processUser(0);
    

    【讨论】:

    • 但这不会同时触发所有copyUser() 函数,因为 .each() 循环将运行到它的完成而不等待任何东西?
    • 会的。我没有意识到 OP 介意循环运行异步。将在一分钟内更新我的答案。
    • 这条线$.when( copyUser($items.eq(i).val()) ).pipe( moveUser() )不是要马上打电话给copyUser()moveUser()吗?并将它们的返回值传递给$.when().pipe() 方法。我认为这不是 OP 想要的。它不会对 ajax 调用进行排序。
    • @jfriend00 - 你是对的。 moveUser 应作为参考传递给 then,但 copyUser 应立即执行,以便将其 Deferred 传递给 when(就像 OP 所做的那样)。我更新了我的答案...
    【解决方案2】:

    我认为您必须停止使用 .each(),因为它会立即运行整个迭代,而您不想这样做。

    这是一种使用完成函数和本地函数的方法:

    function copyMove(moveLocation, urlCopyPrefix, urlMovePrefix, urlSuffix)
        var checked = $('input:checked');
        var index = 0;
    
        function next() {
            if (index < checked.length) {
                var currentInput = checked.eq(index++).val();
                $.get(urlCopyPrefix + currentInput + urlSuffix, function() {
                    $.get(urlMovePrefix + moveLocation + urlSuffix, function() {
                        $('#module-' + moveLocation).before('<li>New Line</li>');
                        next();
                    });
                });
             }
        }
    
        next();
    }
    

    或者,使用延迟:

    function copyMove(moveLocation, urlCopyPrefix, urlMovePrefix, urlSuffix)
        var checked = $('input:checked');
        var index = 0;
    
        function copyUser () { 
            var currentInput = checked.eq(index).val();
            return $.get(urlCopyPrefix + currentInput + urlSuffix);
        }
        function moveUser() {
            return $.get(urlMovePrefix + moveLocation + urlSuffix);
        }
        function cleanup() {
            ++index;
            $('#module-' + moveLocation).before('<li>New Line</li>');
            next();
        }
    
        function next() {
            if (index < checked.length) {
                $.when(copyUser()).pipe(moveUser).then(cleanup);
             }
        }
    
        next();
    }
    

    关于延迟的说明:您必须传递函数引用,而不是函数调用。这意味着您传递的函数名称不带括号。

    【讨论】:

    • 我不同意。 copyUsermoveUser 本身不是延期者。一旦被调用,他们将返回一个 Deferred。 when/then 工作的唯一方法是调用函数,并将返回的 Deferred 传递给 when/then
    • 另外,他绝对必须使用pipe方法。如果您只是添加then 函数,它们不会互相等待。 OP 显然希望 moveUser 在运行 cleanup 之前返回。实现这一目标的唯一方法是通过pipe
    • 好的,切换回pipe()。 pipe 上的 jQuery 文档一文不值。
    • @JosephSilber - 调用 moveUser() 立即启动 ajax 函数。如果您立即执行它,它不能被推迟。 .then(fn) 接受回调或回调列表,而不是延迟。
    • 你部分正确(我部分错误)。 when 采用 Deferred,但 pipe 采用回调。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多