使用ajax回调在每个循环中延迟Jquery [英] Jquery Deferred in each loop with ajax callback

查看:105
本文介绍了使用ajax回调在每个循环中延迟Jquery的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

参考 https://stackoverflow.com/a/13951699/929894 ,我尝试在嵌套的ajax循环.但是,输出未按预期返回.我已经在小提琴中更新了我的代码以供参考. - https://jsfiddle.net/fewtalks/nvbp26sx/1/.

With reference to https://stackoverflow.com/a/13951699/929894, I tried using deferred object in nested ajax loop. However the output is not returning as expected. I have updated my code in fiddle for reference. - https://jsfiddle.net/fewtalks/nvbp26sx/1/.

代码:

  function main() {
    var def = $.Deferred();
    var requests = [];
    for (var i = 0; i < 2; i++) {
        requests.push(test(i));
    }
    $.when.apply($, requests).then(function() {
        def.resolve();
    });

    return def.promise();
}

function test(x){
    var def = $.Deferred();
  test1(x).done(function(){
                setTimeout(function(){ console.log('processed test item', x); def.resolve();}, 1000);
          });
  return def.promise();
}

function test1(items){
    var _d = $.Deferred();
  setTimeout(function(){ 
    console.log('processed test1 item', items); 
    _d.resolve();
  });
  return _d.promise();
}

main().done(function(){ console.log('completed')});

代码包含执行循环的主要功能.在每个循环上,执行一个子功能(测试).在子函数(测试)内部,调用了另一个函数(test1).子函数test和test1都具有AJAX调用声明.对于AJAX调用,我使用了setTimeout属性.我期望像

Code contains a main function which executes loop. On each loop, a sub function(test) is executed. Inside the sub function(test) another function(test1) is called. Both sub functions test and test1 has AJAX call declaration. For AJAX call I have used setTimeout property. I'm expecting an output like

processed test1 item0
processed test item0
processed test1 item1
processed test item0
completed

对于每个循环,我希望函数先执行Test1()然后再执行test();但是我得到的结果是

For each loop, I want the function to be executed as Test1() then test(); However I'm getting the result as

processed test1 item 0
 processed test1 item 1
processed test item 0
processed test item 1
completed

执行test1之后,将完全执行测试功能.为什么函数没有为每个循环顺序执行.

After executing the test1 completely test function is executed. Why the function is not executing sequentially for each loop.

function main(items) {
    var items = items;
    return items.reduce(function (p, index) {
        return p.then(function () {
            return test(index);
        });
    }, $.Deferred().resolve());
}

function test(x) {
    var def = $.Deferred();
    test1(x).done(function () {
        setTimeout(function () {
            log('processed test item', x);
            def.resolve();
        }, 1000);
    });
    return def.promise();
}

function test1(items) {
    var _d = $.Deferred();
    setTimeout(function () {
        log('processed test1 item', items);
        _d.resolve();
    });
    return _d.promise();
}

var items = [0, 1];
function test2(x) {
    var _d = $.Deferred();
    setTimeout(function () {
        log('processed test2 item',x);
        _d.resolve();
    });
    return _d.promise();
}

main([1,2]).done(function(data){test2(items);}).then(function () {
    log('completed')
});

<script src="https://dl.dropboxusercontent.com/u/7909102/log.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

为什么在处理test2函数之前记录完成"?

why 'completed' is logged before processing test2 function?

推荐答案

您的结果符合预期.

您的for循环与完成同步运行,并且两次运行test().

Your for loop runs synchronously to completion and runs test() twice.

test()然后立即调用test1(),因此您首先看到的是test1()运行两次.然后,在每个test1()完成其承诺之后,它将为您的test()日志消息设置计时器.很自然,来自test()的两条日志消息位于来自test1()的两条日志消息之后.

test() then immediately calls test1() so the first thing you see is that test1() gets to run twice. Then, after each test1() completes its promise, it sets the timer for your test() log message. So naturally, the two log messages from test() comes after the two log messages from test1().

请记住,$.when()是并行运行的,所以您通过它的所有承诺都在同时进行.

Remember that $.when() runs things in parallel so all the promises you pass it are in flight at the same time.

如果您要序列化对test(i)的调用,以使下一个调用直到第一个调用之后才发生,所以您需要以不同的方式进行操作.

If you want to serialize your calls to test(i) so the next one doesn't happen until after the first one, then you need to do things differently.

此外,您正在反模式 >通过在不需要创建的地方创建一个递延项.您可以只返回$.when.apply(...).您不需要将其包装在另一个延迟的容器中.

Also, you are using an anti-pattern in main() by creating a deferred where you don't need to create one. You can just return $.when.apply(...). You don't need to wrap it in another deferred.

要序列化对test(i)的调用以获取您指示所需的输出类型,可以执行以下操作:

To serialize your calls to test(i) to get the type of output you indicate you wanted, you can do this:

function main() {
    var items = [0, 1];
    return items.reduce(function(p, index) {
        return p.then(function() {
            return test(index);
        });
    }, $.Deferred().resolve());
}

可产生所需输出的工作演示: https://jsfiddle.net/jfriend00/hfjvjdcL/

Working demo that generates your desired output: https://jsfiddle.net/jfriend00/hfjvjdcL/

.reduce()设计模式通常用于对数组进行串行迭代,调用一些异步操作并等待其完成,然后再对数组中的下一项调用下一个异步操作.使用.reduce()是很自然的,因为我们将一个值传递到下一个迭代(将其链接到下一个迭代)中.它还会返回一个承诺,这样您就可以知道整个过程何时完成.

This .reduce() design pattern is frequently used to serially iterate through an array, calling some async operation and waiting for it to complete before calling the next async operation on the next item in the array. It is a natural to use .reduce() because we're carrying one value through to the next iteration (a promise) that we chain the next iteration to. It also returns a promise too so you can know when the whole thing is done.

这篇关于使用ajax回调在每个循环中延迟Jquery的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆