2016-09-20 76 views
0

我有到位被拆分大型查询到管理的小块,然后用一个简单的AJAX方法吐出了这一点的工具。 AJAX表单的目的地只是一个将某些表单数据委托给函数的脚本,包括处理哪个“块”。未能延时功能,直到后for循环已全面完成

<script>     

var passes = Math.ceil($max/$offset); 

for (i = 0; i < passes; i++) 
{ 

    $.ajax({ 
     type: 'POST', url: 'do.php?p=' + i, data: $('#form" . $i . "').serialize(), 
    success: function(data){ 
     $('#update" . $i . "').append(data); 
    } 
    }); 
} 
</script> 

,因为这可以重复几次,我一直在寻找为执行循环何时脚本(即本身的功能)已完成。

由于这不是什么太时髦,我认为这将是添加if(i == passes -1) { alert('test');}if(i == passes -1) { alert('test');}到循环的结束,像这样的一个简单的例子:

for (i = 0; i < passes; i++) { 

    $.ajax({ 
     type: 'POST', url: 'do.php?p=' + i, data: $('#form" . $i . "').serialize(), 
    success: function(data){ 
     $('#update" . $i . "').append(data); 
    } 
    }); 

    if(i == passes -1) { alert('test');} 

} 

....但它加载这个作为在页面加载之前,在循环之前。

同样,在之后添加一个简单功能循环也获得了相同的结果。

我本来以为(但我在JS挺新鲜的),它会试图执行的“i”的第二个实例之前完成一个循环,但它似乎并没有这样做 - 页面的行为像所有请求都会立即发送,完成循环,执行代码,然后允许“成功”内的函数在自己的时间内回显。这似乎更加明显,因为它有时会在第一次之前追加第二次迭代i的结果。

问题...

1)因为我已在我如何构成的循环,考虑到目的的错误?

2)为什么循环似乎在循环之后执行代码时,它看起来像它仍然会在处理循环本身?

我试图实现

每个循环应该执行MySQL查询,回放功能的HTML输出,然后移动到下一个前打印出来。它确实做到了99%正确,只是偶尔出现的问题并不总是按顺序排列。

毕竟循环已经完成,并追加到容器中,我想运行一些代码来确认操作完成。

许多在此先感谢,希望这是不够清楚

+1

看看:[为什么我的变量在函数内部修改后没有改变? - 异步代码引用](http://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – Andreas

+1

使用承诺。或者对于简单的ajax,使用Callback。 –

+0

您可以对函数使用递归调用,将其添加到$ .ajax的成功参数中。这会按照您希望的顺序加载所有内容。 –

回答

1

这是针对您的问题的“承诺”解决方案。

首先,分解每一个进入,做一个工作单元的功能:

function makePass(i) { 
    return $.ajax({ 
     type: 'POST', url: 'do.php?p=' + i, data: $('#form' + i).serialize() 
    }).then(function(data) { 
     $('#update' + i).append(data); 
    }); 
} 

然后你就可以做出一个通用的函数,伪递归将调用所提供的功能所需的号码,主叫每次用当前通号它,最后返回一个新的“解决”的承诺一次通已经完成:

function makeNPasses(f, n) { 
    var i = 0; 
    return (function loop() { 
     if (i < n) { 
      return f(i++).then(loop); 
     } else { 
      return Promise.resolve(); 
     } 
    })(); 
} 

然后,您可以注册一个处理程序,一旦一切都做,要调用:

var passes = Math.ceil($max/$offset); 

makeNPasses(makePass, passes).then(function() { 
    console.log("All done!"); 
}); 
+0

Brilliant。完全符合计划。我必须研究它才能真正理解这是如何完成的,但它看起来像是一个绝妙的解决方案。谢谢! –

+0

@ChrisJ真正的“神奇”在于'loop()'函数中,它可以重复调用自己所需的次数,并且还可以确保AJAX调用不会全部并行进行。 – Alnitak

-1

发出Ajax请求同步:

所有Ajax请求:

$.ajaxSetup({ async: false }); 

个人:

$.ajax({ 
    async: false, 
    ......... 
}); 
+0

不,不会*使用同步请求 – Alnitak

0

的Javascript有一个异步流程。它不会等待上述请求获取da ta从某个地方......相反,它只是连续发射声明。

为了避免这种情况,有3个选项。

  1. 理想的方法是使1个单HTTP请求到服务器,并获得在JSON阵列的形式的所有数据。这将更加高效,简单和省时,并遵循最佳实践。
  2. 进行ajax的异步调用。你会在这个答案jQuery ajax success anonymous function scope得到有关它的好信息。但是,再次推荐回调,不要做异步错误。相反,.when().then()更容易..因为最终他们也是回调。

  3. 递归函数可以帮助你完成这样的任务。这是一种肮脏的方法,因为ES5不允许使用递归函数进行更深入的迭代。但ES6确实允许它进行10000次迭代。但它不是一个好方法。它增加了开销和瓶颈你的页面加载。

+0

我将请求分成块的原因是每个块在数据库表中处理大约2500行。在单个请求中执行此操作时,会导致内存和服务器性能方面的巨大问题,因为一个请求可能导致250,000多个结果行。 该AJAX是相当快速和功能,但刚刚出现问题。 这是否有助于澄清为什么我这样做? –

+0

当然可以。 ! @ChrisJ –

+1

但是.promise()系统肯定会对这样的应用程序有好处。 http://www.htmlgoodies.com/beyond/javascript/making-promises-with-jquery-deferred.html –

-1

AJAX调用是异步的,因此它们不能用在循环结束之前成功(如JavaScript是非阻塞)。事实上你所想要做的是AJAX调用后,不只是循环(这是同步)后进行动作,所以我会或者使用承诺或链接或聚合成功的事件,如以下建议:

var passes = Math.ceil($max/$offset); 
for (i = 0; i < passes; i++) { 
    $.ajax({ 
     type: 'POST', 
     url: 'do.php?p=' + i, 
     data: $('#form' + i).serialize(), 
     success: function(data){ 
      $('#update' + i).append(data); 
      resolve(); 
     }, 
     error: reject 
    }); 
} 

var resolved = 0; 
function resolve() { 
    if(++resolved >= passes) { 
     alert('test'); 
    } 
} 

function reject() { 
    alert('One of AJAX requests failed'); 
} 
+0

不幸的是,这仍然不起作用。 '测试'提示将随机出现在结果集内。经过8次迭代测试,它在循环结束前的一个随机点发出警报 –

+0

这是不正确的代码 - 循环内的“i”没有正确绑定到当前迭代计数,当它用于'成功'处理程序。 – Alnitak

+0

这可能是我的错,因为使用php'$ i'作为父迭代,而JS'i'作为我的子迭代,这可能使它看起来像在这种情况下是同一个,抛弃了作者答案 –