0

I have a function that uses a jquery .each() selector to populate a table by obtaining the id of each span with a particular class, and then passing that id into an Ajax function.

function populate(){
                  $('#thelist span').each(function()
                    {
                        let id = this.id;
                        let url = `importer.php?id=${id}`;
                         $.ajax(
                          {
                            url: url,
                            success: function(result)
                              { 
                                $("#"+id).html(result);
                              }
                          });
                    })
              };

My question is how to increase the performance. I understand that .each() is causing the delay. Is there a better way to write this?

haz
  • 740
  • 1
  • 11
  • 20
  • 1
    Use benchmark to test diff solutions: https://jsperf.com/foreach-vs-jquery-each/9 – Leszek P Jul 13 '17 at 09:34
  • 1
    Please have a look here: https://stackoverflow.com/questions/11887450/each-vs-for-loop-and-performance – Mihai Alexandru-Ionut Jul 13 '17 at 09:36
  • 3
    Edit your backend to accept all the ID's at once, and return the appropriate content, then do **one single** ajax request – adeneo Jul 13 '17 at 09:37
  • 2
    The problem is too many simultaneous ajax request (if there is a session start in your importer.php then you have also a lock of this). Try to group all request in one and do one bulk request (ex importer.php?ids=1,2,3,4,5) – Luca Rainone Jul 13 '17 at 09:38
  • A better way would be too put a class on the spans - currently it has to look for an element with an id then look for all children spans, could help a little bit, not much though – treyBake Jul 13 '17 at 09:44

4 Answers4

2

Part of the solution is to not use jQuery for this. Native loops (for and while) are incredibly performant, even the native forEach offers better performance. But that is not the whole story here, you're performing a request on each loop, which is architecturally a bad idea. That is the crux of the issue.

What I would do and recommend is to loop through your elements, store the ID's inside of a queue (an array will do) and then once you've done this, serialise the ID's and send them to the server all at once.

function populate() {
    let ids = [];

    $('#thelist span').each(function() {
        let id = this.id;
        ids.push(id);
    });

    $.ajax({
        type: "POST",
        url: "importer.php",
        dataType: "json",
        data: JSON.stringify({ ids: ids }),
        success: function(result) {
            $("#" + result.id).html(result.value);
        }
    });
};

What I am proposing here is an architectural change. Your importer should accept the JSON of ID's that we send. Then the result should return a JSON object with an id and value property. The id property matching the DIV and the value containing your HTML.

I also think you could benefit from switching over to a native for loop instead of using jQuery's each iterator. The problem you have isn't a result of jQuery's each method, but I would consider moving away from it.

Dwayne Charrington
  • 6,524
  • 7
  • 41
  • 63
  • thanks for your suggestion, I did switch to a native for loop and found a big increase in speed in my application – haz Jul 14 '17 at 02:20
1

The each loop doesn't cause a delay, but the ajax call does because it is an asynchrone call waiting for the response of the server. You can't avoid the delay of something loaded from a server. You can show a loader animation or hide the content while the data are loaded.

renaud
  • 11
  • 3
0

Using so many asyncronous petitions cause delay and even headaches if not controlled properly, try to avoid them if possible using like this example, since they doesn't have to return in the same order as they have been done.

Maybe you should consider instead of iterating the ajax function, iterate over the ajax response, and change how server returns data; instead returning one specific id, return all of them, and check if its contained in the table to show it. Something like this:

function popuplate(){
  let url = 'importer.php';
  $.ajax({
    url: url,
    success: function(result){ 
      $.each(result,function(i,r){
        $("#"+r.id).html(r.result);
      });
    }
  });
}
Diego N.
  • 562
  • 3
  • 10
0

This is my attempt to convert .each() to a for loop:

function populate(){
                  var myID = $('#thelist span'); //collect all spans as array
                  for (var i = 0, len = myID.length; i < len; i++) //for loop
                    {
                        let myid = myID[i].id; //span at count i in array as number
                        let url = `importer.php?id=${myid}`;
                         $.ajax(
                          {
                            url: url,
                            success: function(result)
                              { 
                                $('#'+myid).html(result);
                              }
                          });
                    })
              };

I did obtain a significant increase in performance.

haz
  • 740
  • 1
  • 11
  • 20