1

I have a jQuery post method whicih looks like this:

$.post("/SearchCompetitor/Index", { username: _username }, StartLoading())
                           .done(function (data) {
                               if (data !== "UsernameError") {
                                   StopLoading();
                                   var brands = $('<table />').append(data).find('#tableProducts').html();
                                   $('#tableProducts').html(brands);
                                   $("#tableProducts").simplePagination({

                                       // the number of rows to show per page
                                       perPage: 10,

                                       // CSS classes to custom the pagination
                                       containerClass: '',
                                       previousButtonClass: '',
                                       nextButtonClass: '',

                                       // text for next and prev buttons
                                       previousButtonText: 'Previous',
                                       nextButtonText: 'Next',

                                       // initial page
                                       currentPage: 1

                                   });
                                   var header = $('<div />').append(data).find('.bs-glyphicons').html();
                                   $('.bs-glyphicons').html(header);
                                   $('#tableProducts thead, #header').fadeIn("slow");
                                   $('#emptyText').hide();

                               }
                               else {
                                   StopLoading();
                                   ShowMessage("No eBay user was found under: " + $('.txtSearch').val());
                               }
                           })
                           .fail(function (data) {
                               StopLoading();
                               ShowMessage("Something went wrong, please try again!");
                           });

When the post data object doesn't contains a lot of items inside then its fairly okay and it loads without problems...

But when I'm updating the table with 2000+ items inside, it presents a huge issue, I was testing it on firefox browser and it literally crashes every time I work with 2000 + returned items...

My question is, is there any way to avoid browser freezing, maybe some "client side async method" like C# has when using async method to prevent user UI from freezing when working with big chunks of data??

User987
  • 3,663
  • 15
  • 54
  • 115
  • 1
    Try to avoid direct DOM injection (`.html()` and `.text()` in JQuery and `.innerHTML` and `.textContent` in plain JS) until absolutely necessary. Combine injections into fewer calls if possible. And, consider filtering the results of the AJAX call so that you aren't injecting 2000+ records all at once (who really needs to see 2000+ records on one page?). – Scott Marcus Dec 23 '16 at 20:25
  • @ScottMarcus I'm actually trying to break the data into smaller chunks, enabling paging in the end for the user. As you can see im using the jquery plugin to do that, but um it's not really an effective way of doing it this way.. Could you show me what you ment exactly by your answer , in a more practical form (answer) so that I can accept it if it works ? – User987 Dec 23 '16 at 20:27
  • 1
    Is the returned data `html`? What is purpose of `StartLoading()` call? – guest271314 Dec 23 '16 at 20:41
  • @guest271314 startloading(); basically just adds the class to the body of the HTML which represents a loading icon while the data is being fetched – User987 Dec 23 '16 at 20:45
  • @User987 `$.post()` expects the expected response type as a string at third parameter. See also [jQuery - Can threads/asynchronous be done?](http://stackoverflow.com/questions/26068821/jquery-can-threads-asynchronous-be-done) – guest271314 Dec 23 '16 at 20:45
  • 2
    @guest271314 The docs say that return type is fourth parameter. https://api.jquery.com/jquery.post/ – Scott Marcus Dec 23 '16 at 20:47
  • @ScottMarcus Good catch. `StartLoading()` is still called immediately, not passed as a reference, unless a function is returned from the call. – guest271314 Dec 23 '16 at 20:49
  • @ScottMarcus, guest am I missing something here, did I do something wrong when defining the post itself or ? – User987 Dec 23 '16 at 20:50
  • Guys I was thinking I could return JSON as result and then concatenate it into the table like structure, would that improve the performance ?? – User987 Dec 23 '16 at 20:51
  • @User987 Was incorrect, here, as to which parameter `success` and `dataType` are expected at `$.post()`, which ScottMarcus pointed out; see link to `$.post()` documentation. If `StartLoading()` does not return a function to be called, the function will be immediately invoked. – guest271314 Dec 23 '16 at 20:51

2 Answers2

7

As mentioned in my comment, reducing the amount of records you are injecting into the DOM would probably be the first thing to address (who really wants a single web page with 2000+ records displayed on it). Using pagination (as you say you are working on) will go a long way towards solving the issue.

Second, be very careful about DOM injection points - - try to decrease the frequency with which you modify the DOM as this is a well known bottleneck.

A very effective way to decrease DOM injection is to work with string data and manipulate the string until it is ready to be used in the DOM. Only at that point would you inject it. Also, NEVER inject to the DOM in a loop.

So, what I see in your code that stands some scrutiny is this:

StartLoading() // <-- you are invoking the function with this code

This should be a function reference, not a function call, so the line should be:

$.post("/SearchCompetitor/Index", { username: _username }, StartLoading)

Next, we have this:

var brands = $('<table />').append(data).find('#tableProducts').html();
$('#tableProducts').html(brands);

First, you are appending your AJAX result directly into the DOM and then you are searching what you've just appended (searching the DOM) for the content of #tableProducs. I would suggest you search the data for what you need before appending it into the DOM:

// Find what you need without injecting it into the DOM so you don't
// have to search the DOM for it:
var brands = $(data).find('#tableProducts').html();

// Just append what you need when you need it:
$('<table />').append(brands);

You have this same scenario a bit later in your code with this:

var header = $('<div />').append(data).find('.bs-glyphicons').html();

Again, search the data for what you need BEFORE injecting it into the DOM.

Lastly, consider whether you should be using .html() or .text(). The former causes the content to be parsed by the HTML parser and the latter doesn't. If the content contains markup, yes you will want .html(), but if not, .text() can be faster.

Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • 1
    `"
    "`, `"
    "` are valid selectors to pass to `jQuery()`, internally `jQuery()` will insert closing ``, `` tag at returned jQuery object.
    – guest271314 Dec 23 '16 at 20:55
  • 1
    @guest271314 It's a legal selector, but it's not legal HTML and it's use doesn't buy you anything, but potential confusion. See: http://stackoverflow.com/questions/32223415/does-jquery-can-use-an-end-tag-as-a-selector – Scott Marcus Dec 23 '16 at 20:57
  • 1
    Not sure what confusion would be? Agree, tend to use `"
    "`, here, though not exclusively. Either approach return same result, and is not issue at Question.
    – guest271314 Dec 23 '16 at 20:59
  • @ScottMarcus You've explained it splendidly! I understand the issue now more better. I'm just not sure where to start with the paging itself, since the table content is filled with post data... ? Would I first filter the first 10 elements of the returned HTML and then inject it into the DOM itself? How would I then implement the rest of the pages... This is the part that confuses me most... – User987 Dec 23 '16 at 21:00
  • 1
    @guest271314 I understand and that's why I mentioned it as an aside in the answer. But, rather than: `$("
    ")` or `$("
    ")`, why not use the simplest selector of: `$("div")`?
    – Scott Marcus Dec 23 '16 at 21:00
  • 2
    `$("div")` does not create an element, but references existing `"div"` elements. `"div"` is a selector, `"
    "` or `"
    "` create a new `
    ` element.
    – guest271314 Dec 23 '16 at 21:01
  • @ScottMarcus, guest guys should I post another question regarding the paging issue and how to filter the first 10 elements of the returned html ? – User987 Dec 23 '16 at 21:03
  • @User987 It's hard to say without knowing what the response looks like, but first I would check to see if there was a parameter you could pass UP to the server in the AJAX call that would cause the server to only send back a group of records (1-100, 101-200, etc.). That would be best. If you can't do that, you'll have to persist the data yourself (localStorage can help here) and filter it yourself. – Scott Marcus Dec 23 '16 at 21:03
  • @guest271314 Ah, my bad. It's been a while since I've used JQuery. Thanks. Answer modified to remove those comments. – Scott Marcus Dec 23 '16 at 21:03
  • @ScottMarcus No worries. Used inaccurate terminology at first comment at your Answer, `"
    "`, `"
    "` are not valid `css` selectors; the pattern is a jQuery feature for use with `jQuery()` function.
    – guest271314 Dec 23 '16 at 21:11
1

I had a similar problem updating element that contained 1000+ DIV elements with ajax call: replacing it with mere 300 DIVS froze the browser.

Funnily, the problem doesn't seem to be in amount of fetched elements but in overwriting the element. I solved it by emptying the element first, like in your case

$('#tableProducts').html('');
$('#tableProducts').html(brands);
Konservin
  • 997
  • 1
  • 10
  • 20
  • This was the correct answer for me. ScottMarcus' answer is basically saying don't insert a lot of DOM elements if you don't have to, which is good advice if you can; but I had a situation where it was really unavoidable. For my case Konservin's approach worked perfectly :) – David R. Jul 24 '21 at 03:05