-3

Current code

Updated I need the bellow to work with async false as on async true some uploads do not hit the server. The UI just needs to not freeze with async false. Or need a way I can control the que?

$("#goLive" ).click(function() {
        //This is fadein Spinner only apears at end of upload?
        $('.containerFixed').fadeIn();

        var subMit = "{{$client->website}}/api/key/{{$client->apikey}}/push";

        var i = 0;

        $.each(Data, function(key, value) {

            $.ajax({
                type: 'POST',
                contentType: 'application/json',
                url: subMit,
                async : false,
                dataType: "json",
                data: JSON.stringify(Data[key]),
                success: function(){

                   i++;
                    console.log(i, Data.length);
                   if(i >= Data.length){

                       $('.containerFixed').fadeOut();
                   }
                },
                error: function(){
                    i++;
                    console.log(i, Data.length);
                    console.log('Connection Failed');

                    if(i >= Data.length){

                        $('.containerFixed').fadeOut();
                    }

                }

            });
        });
Brent
  • 2,385
  • 10
  • 39
  • 63
  • Your `success` function, seems wrong to me... – Hackerman Jul 25 '14 at 15:06
  • Everything works here until i use async true.. which i need for a popup loader. – Brent Jul 25 '14 at 15:09
  • Try implementing `.fadeIn()` "popup spinner" within `beforeSend` settings, and `.fadeOut()` portion within `ajaxStop` event - fired at last indexed item . fwiw, i.e.g., http://stackoverflow.com/questions/24590765/jquery-loader-gif-and-alert-message/24591517#24591517 – guest271314 Jul 25 '14 at 16:10
  • 2
    If you use `async:false` your browser _will_ freeze. You can't have a cake and eat it too. – John Dvorak Jul 28 '14 at 08:48

4 Answers4

2

Here is a solution that will make the uploads one by one without using async: false while still using asynchronous i/o and not freezing the browser by using promises for synchronization.

You should definitely read mine and Felix's answer on How to return the response from an AJAX call first and make sure you understand the solution before using it.

It does not contain all the complicated logic you've had counting things manually and in fact relies on promises to take care of the concurrency for you. It will make the requests one by one.

Here it is:

$( '#goLive' ).click( function() {

    var subMit = "{{$client->website}}/api/key/{{$client->apikey}}/push";
    var i = 0;

    // The initial item in the queue of actions is the fadeIn action itself, when 
    // the fade in is done we start making requests, change to $.Deferred().resolve()
    // and move the fadeIn back up if you don't want to wait for it 
    var p =  $( '.containerFixed' ).fadeIn().promise(); 

    Data.forEach( function( el, i ) {   // for each item in the data chain
        p = p.then( function() {        // after the last action is done, make a new $.ajax
            return $.ajax( {
                type        : 'POST',
                contentType : 'application/json',
                url         : subMit,
                dataType    : 'json',
                data        : JSON.stringify( el )  // you probably don't need stringify here.
            } ).then( 
                function() {
                    console.log( 'done with ', i );     // log it
                }, 
                function() { 
                    return $.Deferred().resolve();      // suppress request failure
                } 
            );
        } );

        p.then( function() {                    // when all the actions are done
            $( '.containerFixed').fadeOut();    // when all done - fade out
        } );
    } );
} );
Howdy_McGee
  • 10,422
  • 29
  • 111
  • 186
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • I'd place the queue somewhere more global. `#goLive` could receieve a second click while the first is being resolved. Or does OP debounce the button (he should)? – John Dvorak Jul 28 '14 at 09:03
  • @JanDvorak I agree - this answer does not perform any sort of separation of concerns. Personally I do not like having selectors in my code at all. It should definitely be debounced too. – Benjamin Gruenbaum Jul 28 '14 at 09:04
  • Thanks Ben, worked a charm I will add that tomorrow when it comes available. Only one issue the animation stops before the end? – Brent Jul 28 '14 at 09:04
  • 1
    Why wait for the fadeIn to be finished ? – Denys Séguret Jul 28 '14 at 09:11
  • @dystroy the other answer did that and I assumed that he talked with the OP. my first revision just had `$.Deferred().resolve()` – Benjamin Gruenbaum Jul 28 '14 at 09:13
1

Try

$("#goLive" ).click(function() {
        //This is fadein Spinner only apears at end of upload?

        var subMit = "/echo/json/";

        var i = 0;
        var Data = new Array(100);
        $.each(Data, function(key, value) {

            $.ajax({
                beforeSend : function () {
                   $(".containerFixed").fadeIn("slow");
                },
                type: 'POST',
                contentType: 'application/json',
                url: subMit,
                async : true,
                dataType: "json",
                data: JSON.stringify(Data[key]),
                success: function(){

                   i++;
                    console.log(i, Data.length);
                   if(i >= Data.length){

                       $('.containerFixed')
                       .html("loading complete...")
                       .delay(1000)
                       .fadeOut("slow");

                   }
                },
                error: function(){
                    i++;
                    console.log(i, Data.length);
                    console.log('Connection Failed');

                    if(i >= Data.length){

                        $('.containerFixed').fadeOut();
                    }

                }

            });
        });
});

jsfiddle http://jsfiddle.net/guest271314/BwVzw/

guest271314
  • 1
  • 15
  • 104
  • 177
  • 2
    Whether or not this solves the problem, you could make this a much better answer by adding some explanation of what you did rather than just dumping code. – Sam Hanley Jul 25 '14 at 17:15
  • @sphanley At OP "100 records" of `Data` content-type , content-length , not appear clearly defined. Defined as `array` with 100 items , respectively. Moved `.fadeIn()` to `beforeSend` settings function , commented out `async : false` . Thanks – guest271314 Jul 25 '14 at 22:04
  • This does not work with async : true some uploads dont make it where as async false they all go up. – Brent Jul 28 '14 at 08:46
  • @Brent Adjusted async to `true` , each item within `Data` appear to be processed, logged at console ? See jsfiddle . Thanks – guest271314 Jul 28 '14 at 15:23
1

From the jQuery #ajax documentation

Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active. As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the success/error/complete callback options instead of the corresponding methods of the jqXHR object such as jqXHR.done() or the deprecated jqXHR.success().

While you have not explicitly stated why you need these requests to happen synchronously, and the code doesn't indicate a need for it, I'm going to first recommend removing the async: false option.

However, if you truly need these requests to be executed in order, here is a code sample that will do the trick without the use of the deprecated async: false option, and instead properly using the complete callback option:

var subMit = "{{$client->website}}/api/key/{{$client->apikey}}/push";
var requestData = [];
$.each(Data, function(key, value) {
    requestData.push(JSON.stringify(Data[key]));
});

$("#goLive" ).click(sendRequests);

function sendRequests() {
    $('.containerFixed').fadeIn();

    var i = 0;

    function complete() {
        i++;
        if (i >= requestData.length) {
            $('.containerFixed').fadeOut();
        } else {
            sendRequest(i, complete);
        }
    }

    sendRequest(i, complete);
}

function sendRequest(i, complete) {
    $.ajas({
        type: 'POST',
        contentType: 'application/json',
        url: subMit,
        dataType: "json",
        data: requestData[i],
        error: function(){
            console.log('Connection Failed');
        },
        complete: complete
    });
}

I have removed the async: false option and instead manually implemented the behavior you are looking for. For brevity, I removed some of the logging statements that I assume were non-essential. I also assumed that Data is a static map and therefore requestData is safe to reference asynchronously. Of course, you could choose to create the requestData inside of the sendRequests function to protect yourself, as well as scope these functions differently should you have more case-particular needs.

tommyTheHitMan
  • 482
  • 2
  • 8
0

Guess $('.containerFixed').fadeIn(); is async, it will gradually show during a set of time using timeouts or interval (not sure about how it is implemented). Then you sync ajax POST blocks and it only "fade in" after the post is complete.

Any work that is done you should do in the success and/or error callbacks and let in be an async post.

Prusse
  • 4,287
  • 2
  • 24
  • 29