1

I've been working on getting a function written to:

1) Process an input array using $.ajax calls to fill an output array (below this is inputList)

2) Below is what I have, but I'm having issues with it:

  • requestData(), when I call it, runs straight through to processing the outputList array without having fully populated/filled it - it puts one value into it then starts to process that, but the function still apparently runs on seperately to the subsequent processing asynchronously. I need it to be fully synchronous so that it does not return until the inputList array has been fully processed.

  • I'm not seeing the browser repainting the div that has its html updated on every call of the runajax() function - I'm attempting to do this with a setTimeout.

3) I've set the ajax request to be synchronous (async : false) - but this doesn't seem to help

I've tried to use jQuery's $.when to provide an ability to ensure that everything gets called in sequence - but clearly I'm not doing this correctly.

Would appreciate any help - I've asked previous related questions around this and had some useful help - but I've still not resolved this!

Thanks

//declare holding function requestData - expects a non-empty input data array named inputList
    function requestData() {

//declare inner function runajax
        function runajax() {

            if(inputList.length > 0) {
//get first item from inputlist and shorten inputList
                var data = $.trim(inputList.shift());

                function getData() {
//send the data to server
                    return $.ajax({
                        url: 'sada_ajax_fetch_data.php',
                        cache: false,
                        async: false,
                        method: "post",
                        timeout: 2000,
                        data: {
                            requesttype: "getmydata",
                            email: encodeURIComponent(data)
                         }
                    });
                }

                function handleReturnedData (response) {
                    response = $.trim(decodeURIComponent(response));
//update the div inner html
                    if(response == "Failed") {
                        $('#fetchupdatestatus').html('There was an error retrieving the data you requested!'); 
                    } else {
                        $('#fetchupdatestatus').html('The item returned was '+response);                    
                    }

//add the response from ajax to the end of the outputList array
                    outputList.push(response);
//set up the next ajax call
                    var doNextBitOfWork = function () {
                        runajax();
                    };
//call setTimeout so that browser shows refreshed div html
                    setTimeout(doNextBitOfWork, 0);
//return
                    return $.when();
                }

//do the next ajax request and response processing
                return getData().done(handleReturnedData);

            } else {
//did the last one so return
                return $.when();
            }
        }
//kick off the ajax calls
        runajax();
    }

    var inputList = new Array();
    var outputList = new Array();

    .....load +/- 100 values to be processed using ajax into array inputList

    requestData();

    .....process stuff in array outputList
    .....etc

1 Answers1

0

There was my answer with "you're doing it wrong" earlier, but then I just decided to show, how you can do it (almost) right: https://jsfiddle.net/h4ffz1by/

var request_maker = {
  working: false,
  queue: [],
  output: [],
  requestData: function(inputList) {
    if (request_maker.working == true) {
      return false;
    }
    request_maker.output = [];
    request_maker.working = true;
    while (inputList.length > 0) {
      var data = $.trim(inputList.shift());
      request_maker.queue.push(data);
    }
    console.log(request_maker.queue);
    request_maker.doTheJob();
    return true;
  },

  doTheJob: function() {
    current_data_to_send = request_maker.queue.shift();
    console.log(current_data_to_send);

    if (typeof current_data_to_send != 'undefined' && request_maker.queue.length >= 0) {


      $.ajax({
        url: '/echo/json/',
        cache: false,
        method: "post",
        timeout: 2000,
        data: {
          requesttype: "getmydata",
          email: encodeURIComponent(current_data_to_send)
        },
        success: function(data, status, xhrobject) {
          console.log(xhrobject);
          request_maker.handleReturnedData(data);

        },
      });
    } else {
      request_maker.working = false;
      console.log('all data has been sent');
    }
  },
  handleReturnedData: function(response) {
    console.log(response);
    response = $.trim(decodeURIComponent(response));
    //response= 'Failed';//uncomment to emulate this kind of response
    if (response == "Failed") {
      $('#fetchupdatestatus').append('There was an error retrieving the data you requested!<br/>');
    } else {
      $('#fetchupdatestatus').append('The item returned was ' + response + '<br/>');
      request_maker.output.push(response);
    }
    request_maker.doTheJob();
    if (request_maker.working == false) {
      console.log('all requests have been completed');
      console.log(request_maker.output);
    }
  }
}

inputList = [1, 2, 3, 4, 5, 6];
if (request_maker.requestData(inputList)) {
  console.log('started working');
}

if (!request_maker.requestData(inputList)) {
  console.log('work in progress, try again later');
}

Note that I've changed request path to jsfiddle's ajax simulation link and replaced html() with append() calls to print text in div. The calls are made and get handled in the same order as it is in inputList, still they don't lock user's browser. request_maker.output's elements order is also the same as in inputList.

Have in mind, that you will need to add error handling too (probably just a function that pushes 'error' string into output instead of result), otherwise any ajax error (403/404/502, etc.) will get it "stuck" in working state. Or you can use complete instead of success and check request status right there.

UPD: Answer to the question: you cannot get both. You either use callbacks and let browser repaint inbetween asynchroneous requests or you make requests synchroneous and block browser untill your code finished working.

UPD2: There actually is some information on forcing redraw, however I don't know if it will work for you: Force DOM redraw/refresh on Chrome/Mac

Community
  • 1
  • 1
haldagan
  • 911
  • 5
  • 16
  • Thanks @haldagan - I'll give this a try! – Chris Jones Mar 30 '16 at 09:14
  • -moved this to answer post- – haldagan Mar 30 '16 at 09:20
  • this works great in terms of the browser repaint BUT the problem I still have is that I need to ensure that the script that contains this doesn't proceed UNTIL all processing has been completed - and we have the output in place. IE: if I put e.g. console.log("we reached here because everything has been processed and output is ready for further processing"); right after your last "}" in above, then I don't want to see that until we're 100% done? – Chris Jones Mar 30 '16 at 10:28
  • ..cont: Right now if I add that to your fiddle, then I see it right after "stated working", obviously. I don't want to have to encapsulate all my following code in a callback, as it is complex and staggered. Any ideas? – Chris Jones Mar 30 '16 at 10:28
  • I'm not really sure of why will you need this, yet you can add `async:false` to ajax request, but then you will need to get rid of `working` flag and all checks with it as long as it will have no use anymore. Note, that requests/data will be sent/recieved synchroneously, yet the page will be re-rendered only at the end and not as soon as data is recieved (at least in chrome). You need to choose, what do you want more - "simplicity" of the code, or the code working as you've planned. You can not actually make interpreter `sleep` to let browser render page - you'll need callbacks either way. – haldagan Mar 31 '16 at 06:08
  • P.S.: I'm wondering why were you using `when`in the first place as it just provides callbacks for asynchroneous events (especially if you don't want it to be asynchroneous and don't want to use callbacks). – haldagan Mar 31 '16 at 06:18
  • I've updated my answer to actually answer your question. – haldagan Mar 31 '16 at 07:02