0

I believe I am timing out a web service by making too many calls in a short period of time. I am wanting to wait about 5 seconds between each iteration of a $.each loop in my jquery.

Here is a look at what I have:

function submitMyList(myList) {
    $.each(JSON.parse(myList), function (key, value) {
        setTimeout( function(){ 
            $.ajax({
                type: 'POST',
                url: '@Url.Action("submitMyList", "myController")',
                dataType: 'html',
                contentType: 'application/json; charset=utf-8',
                data: JSON.stringify(//passing my values),
                success: function (result) {
                    //success code
                },
                error: function (result) {
                    //error code
                },
                complete: function () {
                    //completion code
                }

            });
        }, 5000)     
    });
}

This still is execution extremely quick, one after another.

Johnrad
  • 2,637
  • 18
  • 58
  • 98
  • Instead of trying to make the same request every five seconds, wait until the previous request has finished before making the next one. – zzzzBov Feb 24 '15 at 15:03
  • @zzzzBov I am not really wanting to perform this like that. Each request can take about 1-2 minutes to complete. My list could potentially be as high long as about 70 entries. So performing the submission could take a long time that way. – Johnrad Feb 24 '15 at 15:16

2 Answers2

3

What's happening is that when you run your "each", you set a lot of timers immediately, which all wait 5 seconds and then run at the same time. This is due to the fact that the each just wants to finish it's loop as quickly as possible, and it runs all of it's functions (including the "setTimeout" function). It doesn't have to wait for anything, so runs of and sets a whole lotta' timeouts :)

Easiest solution would be to let the setTimeout wait 5000 * num milliseconds and increase the num with every loop, something like this:

function submitMyList(myList) {
  var num = 0;
  $.each(JSON.parse(myList), function (key, value) {
    num++;
    setTimeout( function(){ 
        $.ajax({
            type: 'POST',
            url: '@Url.Action("submitMyList", "myController")',
            dataType: 'html',
            contentType: 'application/json; charset=utf-8',
            data: JSON.stringify(//passing my values),
            success: function (result) {
                //success code
            },
            error: function (result) {
                //error code
            },
            complete: function () {
                //completion code
            }

        });
    }, 5000*num);     
  });
}
Eric Mahieu
  • 327
  • 1
  • 6
  • It should work, look at this minimal test in JSFiddle: http://jsfiddle.net/cy0uqLnj/ To add to my answer, what would be even better is to use the "success" to set a new timer, advantage is you don't have the risk to "heap up" calls if there's a delay in the calls. Disadvantage is everything stops if a request fails. – Eric Mahieu Feb 24 '15 at 15:09
  • I apologize this does work, I got myself a little turned around. I am still a little confused as to why it works. The working in the first phrase is a little confusing to me. – Johnrad Feb 24 '15 at 15:18
  • No problem, happy it works. Have clarified my answer a bit, hope it helps. – Eric Mahieu Feb 24 '15 at 15:25
2

An approach of this kind could work:

$(document).ready(function () {
    var a = new Array("Apples", "Bananas", "Oranges")
    jQuery.each(a, function (idx, val) {
        setTimeout(function() {
            console.log("At "+idx+" Val "+val)
        }, idx * 5000);
    })
})

in your specific case try this:

function submitMyList(myList) {
    var idx = 0;
    $.each(JSON.parse(myList), function (key, value) {
        setTimeout( function(){ 
            $.ajax({
                type: 'POST',
                url: '@Url.Action("submitMyList", "myController")',
                dataType: 'html',
                contentType: 'application/json; charset=utf-8',
                data: JSON.stringify(//passing my values),
                success: function (result) {
                    //success code
                },
                error: function (result) {
                    //error code
                },
                complete: function () {
                    //completion code
                }

            });

        }, idx*5000)
        idx++;     
    });
};

example here: http://jsfiddle.net/1w6uxLxs/1/

The idea You have to multiply your timeout by the number of iterations because what is happening is that the timeouts are set one after another (basically simultaneously), because what happens is that the loop goes through all elements and for each element you instruct the browser (setTimeout) to execute a function after a certain amount of time. By multiplying this amount of time by the index you get the "delay" effect. Have a look at what happens in the console in this example: http://jsfiddle.net/1w6uxLxs/2/

Danilo
  • 2,676
  • 7
  • 32
  • 36
  • Thanks for your help, this does work like a charm. Would you mind explaining why I am having to multiply by `idx` every time the loop iterates? – Johnrad Feb 24 '15 at 15:08
  • I updated the answer trying to explain the idea. Let me know if it's clear. – Danilo Feb 24 '15 at 15:28