JavaScript似乎以错误的顺序执行代码

时间:2012-01-01 22:43:49

标签: javascript jquery asynchronous

我已经看到了JavaScript中最奇怪的行为,并希望能够深入了解造成这种情况的原因。我做了一个小数独求解器应用程序(下面的代码,也可以在wellsjohnston.com/projects上看到),其中一部分有一个板生成器。当你点击'生成板'或'解决'时,jQuery应该改变按钮来说“创建随机板......”或“解决......”。但是,当它们被点击时,没有任何反应。你会认为这根本不起作用 - 但事实并非如此。当我删除代码以更改按钮(即,删除$('。submit_sudoku_board')。text('solve')时,它突然起作用,并且在单击时发生更改(当然不会返回)。任何人都知道发生了什么事?

TL; DR:代码似乎是异步执行的。当求解/板生成递归函数正在运行时,脚本的其余部分将执行。为什么??

谢谢!

编辑:也添加了HTML代码。对不起,如果它很难看......

$(function(){
    $('.submit_sudoku_board').click(function(){
        $('.submit_sudoku_board').text('Solving...');
        sudoku();
        $('.submit_sudoku_board').text('Solve');
    });
    $('.clear_board').click(function(){
        $('.board_input').val('');
        });
    $('.generate_board').click(function(){
        $('.board_input').val('');
        $('.generate_board').text('Creating Random Board...');
        console.log('creating random board...')
        generate_random_board();
        console.log('------done creating board-----');
    });
});

function sudoku()
{
    var sudoku_board = new Array(9);
    for(var i = 0; i < 9; i++){
        sudoku_board[i] = new Array(9);
    }

    var cell, valid = true;
    for(i = 0; i < 9; ++i)
    {
        for(var j = 0; j < 9; ++j)
        {
            cell = '#r' + i + 'c' + j;
            if($(cell).val())
            {
                if(!($(cell).val() > 0 && $(cell).val() < 10))
                {
                    $('.sudoku_message_box').text("Illegal characer found");
                    valid = false;
                    break;
                }
                sudoku_board[i][j] = ($(cell).val());  
            }else{
                sudoku_board[i][j] = 0;
            }
        }
    }
    if(valid)
    {
        var start = new Date().getTime();
        var solved = sudoku_solver(sudoku_board, 0, 0);
        var end = new Date().getTime();
        var solve_time = (end - start)/1000.0;
        if(solved)
        {
            fill_board(sudoku_board);
            $('.sudoku_message_box').text("Solve time: " + solve_time + " seconds");
            $('.submit_sudoku_board)').text('Solve');
        }else{
            $('.sudoku_message_box').text("Sudoku puzzle not solvable");
        }
    }
}

function sudoku_solver(board, row, col){
    if(row == 9)
    {
        return true;
    }else if(col == 9)
    {
        return sudoku_solver(board, row + 1, 0);
    }else if(board[row][col] != 0)
    {
        return sudoku_solver(board, row, col + 1);
    }

    for(var i = 1; i < 10; i++)
    {
        if(can_go(board, row, col, i))
        {
            board[row][col] = i;
            if(sudoku_solver(board, row, col + 1))
            {
                return true;
            }
        }
    }
    board[row][col] = 0;
    return false;
}

function can_go(board, row, col, val){
    for(var i = 0; i < 9; i++)
    {
        if(board[row][i] == val || board[i][col] == val)
        {
            return false;
        }
    }
    var subgrid_row;
    var subgrid_col;

    if(row < 3)
    {
        subgrid_row = 0;
    }else if(row > 5)
    {
        subgrid_row = 6;
    }else{
        subgrid_row = 3;
    }

    if(col < 3)
    {
        subgrid_col = 0;
    }else if(col > 5)
    {
        subgrid_col = 6;
    }else{
        subgrid_col = 3;
    }

    for(i = subgrid_row; i <= subgrid_row + 2; i++)
    {
        for(var j = subgrid_col; j <= subgrid_col + 2; j++)
        {
            if(board[i][j] == val)
            {
                return false;
            }
        }
    }
    return true;
}

function fill_board(board){
    var cell;
    for(i = 0; i < 9; ++i)
    {
        for(j = 0; j < 9; ++j)
        {
            if(board[i][j] != 0)
            {
                cell = '#r' + i + 'c' + j;
                ($(cell).val(board[i][j]));
            }

        }
    }
}

function generate_random_board(){
    var sudoku_board = new Array(9), dummy_board = new Array(9);
    for(var i = 0; i < 9; i++){
        sudoku_board[i] = new Array(9);
        dummy_board[i] = new Array(9);
    }
    for(i = 0; i < 9; ++i)
    {
        for(var j = 0; j < 9; ++j)
        {
            sudoku_board[i][j] = 0;
            dummy_board[i][j] = 0;
        }
    }
    var random_range = Math.floor(Math.random()*10)+ 30;
    for(i = 0; i < random_range; i++)
    {
        var random_x=Math.floor(Math.random()*8) + 1; // generate a random number 1-9
        var random_y =Math.floor(Math.random()*8) + 1; 
        var random_val =Math.floor(Math.random()*8) + 1; 
        if(can_go(sudoku_board, random_x, random_y, random_val))
        {
            sudoku_board[random_x][random_y] = random_val;
            dummy_board[random_x][random_y] = random_val;
        }
    }
    console.log('solving test board');
    var solvable = sudoku_solver(dummy_board, 0, 0);
    console.log('iteration complete');
    if(solvable)
    {
        console.log('found board');
        $('.generate_board').text('Generate Solvable Board');
        fill_board(sudoku_board);
    }else{
        console.log('board failed');
        $('.generate_board').text('board not found');
        $('.board_input').val('');
        generate_random_board();
    }
}





     <div class="sudoku">
                            <div class="sudoku_title">
                                Sudoku Solver in JavaScript
                            </div>
                            <form style="position:relative; left:20%; top:25px;">
    <table cellspacing=0 cellpadding=0 border=1 style="background-color:#FFFFFF;">
        <!-- row 0 -->
        <tr>
            <td class="board"><input class ="board_input" maxlength="1" maxlength="1" type="text" id="r0c0" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r0c1" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r0c2" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r0c3" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r0c4" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r0c5" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r0c6" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r0c7" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r0c8" size="20" /></td>
        </tr> 
        <!-- row 1   -->
        <tr>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r1c0" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r1c1" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r1c2" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r1c3" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r1c4" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r1c5" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r1c6" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r1c7" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r1c8" size="20" /></td>
        </tr> 
        <!-- row 2   -->
        <tr>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r2c0" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r2c1" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r2c2" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r2c3" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r2c4" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r2c5" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r2c6" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r2c7" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r2c8" size="20" /></td>
        </tr>
        <!-- row 3   -->
        <tr>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r3c0" size="20" /></td>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1"  type="text" id="r3c1" size="20" /></td>
            <td class="board board_horizontal board_vertical"><input class ="board_input" maxlength="1" type="text" id="r3c2" size="20" /></td>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r3c3" size="20" /></td>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r3c4" size="20" /></td>
            <td class="board board_horizontal board_vertical"><input class ="board_input" maxlength="1" type="text" id="r3c5" size="20" /></td>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r3c6" size="20" /></td>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r3c7" size="20" /></td>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r3c8" size="20" /></td>
        </tr> 
        <!-- row 4   -->
        <tr>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r4c0" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r4c1" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r4c2" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r4c3" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r4c4" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r4c5" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r4c6" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r4c7" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r4c8" size="20" /></td>
        </tr> 
        <!-- row 5   -->
        <tr>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r5c0" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r5c1" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r5c2" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r5c3" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r5c4" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r5c5" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r5c6" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r5c7" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r5c8" size="20" /></td>
        </tr> 
        <!-- row 6   -->
        <tr>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r6c0" size="20" /></td>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r6c1" size="20" /></td>
            <td class="board board_horizontal board_vertical"><input class ="board_input" maxlength="1" type="text" id="r6c2" size="20" /></td>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r6c3" size="20" /></td>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r6c4" size="20" /></td>
            <td class="board board_horizontal board_vertical"><input class ="board_input" maxlength="1" type="text" id="r6c5" size="20" /></td>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r6c6" size="20" /></td>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r6c7" size="20" /></td>
            <td class="board board_horizontal"><input class ="board_input" maxlength="1" type="text" id="r6c8" size="20" /></td>
        </tr> 
        <!-- row 7   -->
        <tr>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r7c0" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r7c1" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r7c2" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r7c3" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r7c4" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r7c5" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r7c6" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r7c7" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r7c8" size="20" /></td>
        </tr> 
        <!-- row 8   -->
        <tr>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r8c0" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r8c1" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r8c2" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r8c3" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r8c4" size="20" /></td>
            <td class="board board_vertical"><input class ="board_input" maxlength="1" type="text" id="r8c5" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r8c6" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r8c7" size="20" /></td>
            <td class="board"><input class ="board_input" maxlength="1" type="text" id="r8c8" size="20" /></td>
        </tr> 
        <!-- end rows -->
    </table> 
</form>
                            <div class="sudoku_bottom">
                                <div class="submit_sudoku_board">
                                    Solve
                                </div>
                                <div class="sudoku_message_box">
                                    Enter a Sudoku puzzle into the board
                                </div>
                            </div>
                            <div class="clear_board">
                                Clear Board
                            </div>
                            <div class="generate_board">
                                Generate Solvable Board
                            </div>
                        </div>

1 个答案:

答案 0 :(得分:5)

在大多数浏览器中,Javascript在GUI线程上运行。如果您的脚本正在运行,则在您的函数返回之前,GUI不会更新。

允许GUI重新获得控制权并重新绘制此类内容,这会延迟执行实际解决,直到GUI更新为止:

$('.submit_sudoku_board').click(function(){
    $('.submit_sudoku_board').text('Solving...');
    window.setTimeout(function() {
        sudoku();
        $('.submit_sudoku_board').text('Solve');
    }, 10);
});