只有在上一组工作完成后才循环执行一组工作
Posted
技术标签:
【中文标题】只有在上一组工作完成后才循环执行一组工作【英文标题】: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);
);
【问题讨论】:
【参考方案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();
关于延迟的说明:您必须传递函数引用,而不是函数调用。这意味着您传递的函数名称不带括号。
【讨论】:
我不同意。copyUser
和 moveUser
本身不是延期者。一旦被调用,他们将返回一个 Deferred。 when
/then
工作的唯一方法是调用函数,并将返回的 Deferred 传递给 when
/then
。
另外,他绝对必须使用pipe
方法。如果您只是添加then
函数,它们不会互相等待。 OP 显然希望 moveUser
在运行 cleanup
之前返回。实现这一目标的唯一方法是通过pipe
。
好的,切换回pipe()
。 pipe 上的 jQuery 文档一文不值。
@JosephSilber - 调用 moveUser()
立即启动 ajax 函数。如果您立即执行它,它不能被推迟。 .then(fn)
接受回调或回调列表,而不是延迟。
你部分正确(我部分错误)。 when
采用 Deferred,但 pipe
采用回调。以上是关于只有在上一组工作完成后才循环执行一组工作的主要内容,如果未能解决你的问题,请参考以下文章