JavaScript:在循环中等待函数执行完毕后再进行下一次迭代

4
$(function() {
$("#submit").click(function() {


for (var i=1; i<=14; i++)
{
        setID(i); 
        checkField(i);

}

if ($('#pass_fail').val() != "fail")
{ 
//do something
}

当我点击注册表单的提交按钮时,会发生以下情况:

期望的执行顺序:


setID(1);
checkField(1); //等待此操作完成
setID(2);
checkField(2);
setId(3);
checkField(3);
....
if 语句

实际的执行顺序:


循环从 i=1 到 i=14
if 语句
checkField(i) 的执行顺序随机

问题:$('#pass_fail').val() 的默认值为 'pass'。但是通过循环 checkField(i) 可能会将其更改为 'fail'。但由于实际上 if 语句在 checkField(i) 之前执行,因此 $('#pass_fail') 的值始终为 'pass',并且 'do something' 总是被执行。

如何等待 checkField(i) 执行完毕后再进入下一次循环?谢谢!


1
将异步函数转换为同步函数,您可能需要重构checkField以接受下一个checkField的回调。 - Fabricator
1
那么,checkField() 是执行服务器请求吗?为什么不一次性获取所有字段并同时检查它们呢? - Ja͢ck
正确的,checkField() 包含一个 Ajax 调用,它访问一个包含检查不同字段函数的 php 文件。我不能为所有字段执行单个调用的原因是每个调用返回与该字段对应的不同错误消息。如果单个 checkField() 同时检查所有字段,则所有不同字段的错误将显示在同一字段下。 - user2973438
2个回答

3
根据你描述的问题,我假设checkField()会进行某种异步Ajax调用。如果你真的想要将对checkField()的调用串行化,以便第二个调用在第一个完成之前不会被执行,那么你需要改变代码的结构和流程来实现。两种常见的方法是使用回调函数指示调用checkField()的完成,这将触发下一个调用checkField();或者使用promise来实现类似的功能。
以下是回调机制的示例:
$("#submit").click(function() {
    var i = 0;
    function next() {
        i++;
        if (i <= 14) {
            setID(i);
            checkField(i, next);
        } else {
            // all checkField operations are done now
            if ($('#pass_fail').val() != "fail") { 
                //do something
            }
        }
    }
    next();
});

然后,checkField() 必须被修改为在完成异步操作时调用传递给它的回调函数。


如果你正在使用 jQuery 来执行 checkField 中的 ajax 操作,那么使用 jQuery promises 也会相当容易解决这个问题。


0

抱歉,在之前的回复中我没有看到任何循环等待其他函数或内部循环执行完成后再进行下一次迭代的代码。

使用 JQuery 3.3.1

场景: for 循环 中的 var i 将等待内部其他循环完成,然后才会进行下一次迭代值的 i

$(document).ready(function(){

    $("p").click(function() {
    
     var varIDeferred = $.Deferred();
        var varJDeferred = $.Deferred();
        
        /*
        var loopJInside = function(j) {  
            console.log("j is : " + j);
            $("span").html($("span").html() + "<br>j is : " + j);
            varJDeferred.resolve();
            j++;
            console.log("j value after incr is : " + j);
            return j;
        }
        
        // call inside loopJ
        setTimeOut(j = loopJInside(j), 500);
        */
        
        var loopJ = function(valueI) {
        
            for (var j = valueI; j < (3+valueI); ) {
             
         varJDeferred = $.Deferred();
                $("span").html($("span").html() + "<br>j is : " + j);
                j++;
                varJDeferred.resolve();
                
            }
            
            varIDeferred.resolve();
            
            return (valueI+1);
        };
        
        for(var i = 0; i < 3; ) {
            
            varIDeferred = $.Deferred();
            
     $("span").html($("span").html() + "<br>value of i is : " + i);
            
            if (i == 3)
                break;
             
            i = loopJ(i);
        };
        
    });
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>

<p style="cursor:default;border:2px solid black;width:60px;padding:5px;">Click me</p>
<span><span>

</body>
</html>

希望这能帮助到很多人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接