What is the best way of showing progress on an Ajax call?

前端 未结 12 1094
遥遥无期
遥遥无期 2020-11-28 05:17

I have an Ajax call that updates 5,000 records in a database so this takes a lot of time. I have an Ajax \"Loading image\" showing that something is happening, but I am loo

12条回答
  •  天命终不由人
    2020-11-28 05:43

    Create a simple table like this:

    CREATE TABLE progress_data (
      statusId int(4) NOT NULL AUTO_INCREMENT,
      progress float DEFAULT NULL COMMENT 'percentage',
      PRIMARY KEY (id_progress_data)
    );
    

    JQuery code:

    //this uses Jquery Timers http://plugins.jquery.com/project/timers
    $('#bUpdate').click(function() {
        //first obtain a unique ID of this operation - this has to by synchronized
        $.ajaxSetup({'async': false});
        $.post('ajax.php', {'operation': 'beginOperation'}, function(data) {
            statusId = parseInt(data.statusId);
        });
        //now run the long-running task with the operation ID and other params as necessary
        $.ajaxSetup({'async': true});
        $.post('ajax.php', {'operation': 'updateSite', 'statusId': statusId, 'param': paramValue}, function(data) {
            $('#progress_bar').stopTime('statusLog'); //long operation is finished - stop the timer
            if (data.result) {
                //operation probably successful
            } else {
                //operation failed
            }
        });
        //query for progress every 4s, 'statusLog' is just the name of the timer
        $('#progress_bar').everyTime('4s', 'statusLog', function() {
            var elm = $(this);
            $.post('ajax.php', {'operation': 'showLog', 'statusId': statusId}, function(data) {
                if (data) {
                    //set bar percentage
                    $('#progress').css('width', parseInt(data.progress) + '%');
                }
            });
        });
        return false;
    }
    

    Backend code (in PHP):

    if (isset($_POST['operation'])) {
            ini_set("display_errors", false);
            session_write_close();  //otherwise requests would block each other
            switch ($_POST['operation']) {
                /**
                * Initialize progress operation, acquire ID (statusId) of that operation and pass it back to
                *   JS frontend. The frontend then sends the statusId back to get current state of progress of
                * a given operation.
                */
                case 'beginOperation': {
                    $statusId = //insert into progress_data
                    echo json_encode(array('statusId' => $statusId));
                    break;
                }
                /**
                * Return back current progress state.
                */
                case 'showLog': {
                    $result->progress = (float) //SELECT progress FROM progress_data WHERE statusId = $_POST['statusId']
                    echo json_encode($result);
                    break;
                }
                case 'updateSite': {
                    //start long running operation, return whatever you want to, during the operation ocassionally do:
                        UPDATE progress_data SET progress=... WHERE statusId = $_POST['statusId']
                }
            }
        }
        /* Terminate script, since this 'view' has no template, there si nothing to display.
        */
        exit;
    

    I have used this approach in 3 applications already and I must say it is very reliable and fast enogh (the showLog operation is just a simple SELECT statement). It is also possible to use session to store the progress, but that brings a lot of problems, since the session has to be write closed (if it is stored in files), otherwise the showLog AJAX queries will wait for the long operation to finish (and loose sense).

提交回复
热议问题