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

前端 未结 12 1006
遥遥无期
遥遥无期 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:23

    The best I think is using Comet.

    In Comet-style applications, the server can essentially push data to the client (instead of the client request data from the server again and again.). The client needs to only connect to server once. and then server will keep pushing data back to client.

    From Wikipedia:

    Comet is a programming technique that enables web servers to send data to the client without having any need for the client to request it. It allows creation of event-driven web applications which are hosted in the browser.

    And now let's see how Comet works. See the following server-side code. here a while loop is being used, you can instead set your own condition. In the while loop, the page writes a datetime and flushes and then sleeps for 1/2 seconds.

    ASP.NET page code-behind: Service.aspx.cs

    public static string Delimiter = "|";
    
    protected void Page_Load(object sender, EventArgs e)
    {
        Response.Buffer = false;
    
        while (true)
        {
            Response.Write(Delimiter
                + DateTime.Now.ToString("HH:mm:ss.FFF"));
            Response.Flush();
    
            // Suspend the thread for 1/2 a second
            System.Threading.Thread.Sleep(500);
        }
    
        // Yes I know we'll never get here,
        // it's just hard not to include it!
        Response.End();
    }
    

    Client side code - pure JavaScript

    Only make the request once, and then keep checking the data in the readyState === 3 of XMLHttpRequest.

    function getData()
    {
        loadXMLDoc("Service.aspx");
    }
    
    var req = false;
    function createRequest() {
        req = new XMLHttpRequest(); // http://msdn.microsoft.com/en-us/library/ms535874%28v=vs.85%29.aspx
    }
    
    function loadXMLDoc(url) {
        try {
            if (req) { req.abort(); req = false; }
    
            createRequest();
    
            if (req) {
                req.onreadystatechange = processReqChange;
                req.open("GET", url, true);
                req.send("");
            }
            else { alert('unable to create request'); }
        }
        catch (e) { alert(e.message); }
    }
    
    function processReqChange() {
        if (req.readyState == 3) {
            try {
                ProcessInput(req.responseText);
    
                // At some (artibrary) length   recycle the connection
                if (req.responseText.length > 3000) { lastDelimiterPosition = -1; getData(); }
            }
            catch (e) { alert(e.message); }
        }
    }
    
    var lastDelimiterPosition = -1;
    function ProcessInput(input) {
        // Make a copy of the input
        var text = input;
    
        // Search for the last instance of the delimiter
        var nextDelimiter = text.indexOf('|', lastDelimiterPosition + 1);
        if (nextDelimiter != -1) {
    
            // Pull out the latest message
            var timeStamp = text.substring(nextDelimiter + 1);
            if (timeStamp.length > 0) {
                lastDelimiterPosition = nextDelimiter;
                document.getElementById('outputZone').innerHTML = timeStamp;
            }
        }
    }
    
    window.onload = function () { getData(); };
    

    Reference

    0 讨论(0)
  • 2020-11-28 05:24

    I would let the function that is doing the big update record in a SESSION variable its current progress after each single (or so many) update, and use a separate AJAX script to retrieve this progress value from the SESSION and let JavaScript use this to update your progress bar/text.

    0 讨论(0)
  • 2020-11-28 05:24

    I just got an idea while reading the replies.

    JavaScript and PHP share cookies,

    1. Create a cookie with JavaScript when an Ajax call is made.
    2. In an Ajax PHP file increment the value in that cookie with each SQL update.
    3. In JavaScript a recursive function will read that particular cookie and will update progress bar numbers.

    Advantages:

    1. Only 1 Ajax call.
    2. Less load on the server.
    0 讨论(0)
  • 2020-11-28 05:26

    For showing progress during load, I would modify my backend so that it can do selective loading.

    For example,

    var total_rec = 5000;
    var load_steps = 20;
    var per_load = total_rev / load_steps;
    var loaded = 0; 
    while (loaded < total_rec) {
        www.foobar.com/api.php?start=loaded&end=(loaded+per_load);
        loaded += per_load;
    }
    

    Every time the load is done, update the progress bar.

    An alternative way to modify the backend can be

    www.foobar.com/api.php?start=loaded&count=50
    
    0 讨论(0)
  • 2020-11-28 05:29

    I am assuming you are currently using one POST for all records in the batch update and placing the loading image between call and return.

    Rather than having the server wait to return until completing the update, have it return immediately with a special ID for that batch update. Then implement a server call that returns the status of the batch update, which your progress dialog can call to report the progress.

    var progressCallback = function(data){
      //update progress dialog with data
      //if data does not indicate completion
        //ajax call status function with "progressCallback" as callback
    });
    //ajax call status function with "progressCallback" as callback
    
    0 讨论(0)
  • 2020-11-28 05:29

    Something seems fishy.

    I'm not familiar with databases that can't update 5000 records in a flash... So this isn't just a single update you're applying but a record by record update?

    Consider a system which lets a user download 5000 entries and does not mark which ones have been edited and then at the end of making updates applied a single update button which would require that all 5000 records be passed back in some way. That would be worst case.

    So there may be some way to partition the problem such that there is no wait time. Consider for instance a temporary db table (or just in the applications memory, pretty easy by just creating a list of ORM entities... but that's an aside) then when it comes time to commit those updates they can at least be done in a batch without requiring any client/server transfer. It may even be possible to mark the individual fields which were edited so there is nothing more updated on the DB except exactly what changed.

    There are long running processes and I know sometimes you're stuck having to use what someone has provided you with... but perhaps with a bit of thinking you can simply get rid of the wait time.

    0 讨论(0)
提交回复
热议问题