0

I have a problem with my jQuery/Javascript code. All works as expected but after some time the page becomes unresponsive throwing the Unresponsive Script error for jQuery. I am using a jQuery Library for displaying lists as coverflow.

Also, after all calls to backend I have to refresh the particular div and hence I destroy and recreate the div every time the call is made to backend.

Please let me know what is the problem in the structure of the code given below:

(Please note this is just a snippet with important methods. All these methods also have other logic written in them which is not displayed here).

function showAllData(dataFromServer) {
  $('#child').remove();
  $('#parent').append($('<div id="child"></div>'));

  $.each(dataFromServer.someArray, function(index, item) {
    var html = '<li>' + item + '</li>';
    $('#child').append($(html));
  });

  //Attach Event to div
  $("#child").on("click", function() {
    removeTag();
  });
};

$(document).ready(function() {
  //got data from server(Spring MVC) in a var 'dataFromServer'
  //code not written here
  showAllData(dataFromServer);
  $("#child").flipster(); //a coverflow library 
});


$(document).on('submit', '#formSubmit', function(event) {
  event.preventDefault();
  $.ajax({
    url: url,
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    async: true,
    cache: false,
    data: JSON.stringify({
      dataFromClient: dataFromServer
    }),
    type: "POST",
    success: function(data) {
      dataFromServer = data;
      showAllData(dataFromServer);
      $("#child").flipster();
    },
    error: function(xhr, status, error) {
      console.log(xhr.responseText);
    }
  });
  return false;
});

function removeTag() {
  $.ajax({
    url: 'deleteBooks',
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    async: true,
    cache: false,
    data: JSON.stringify({
      keyword: tag,
      dataFromClient: dataFromServer
    }),
    type: "POST",
    success: function(data) {
      dataFromServer = data;
      showAllData(dataFromServer);
      $("#child").flipster();
    },
    error: function(xhr, status, error) {
      console.log(xhr.responseText);
    }
  });
};

Any idea?

[EDIT]: This happens quickly when accessing website on mobile. The page freezes! But when working on desktop version, page becomes unresponsive after some time and error of Maximum Call Stack Size Reached error is thrown.

This can be because of the memory of smartphone. Nonetheless, problem is there in both versions.

Jagrut
  • 922
  • 7
  • 21
  • the unresponsive script error usually occurs when you are trying to run a long loop in js. Try using some kind of lazy loading to shorten the number of loops. on scroll u can add more data on the fly. – chrisgiffy Feb 08 '16 at 10:54
  • @chrisgiffy All data is displayed within screen size. So no scrolling. Also, I do not have many loops and all those loops are kept in check to not go infinite. I am not sure about attaching event or something like that. – Jagrut Feb 08 '16 at 10:58
  • See: [Performance profiling with the Timeline](https://developer.chrome.com/devtools/docs/timeline) – Yogi Feb 08 '16 at 10:58
  • @Roberto I did look for it. But did not find any calls that are going in infinite loops. – Jagrut Feb 08 '16 at 11:12
  • I think @user978612 has done some good troubleshooting. Also see this question about using jQuery "off()" when adding a click handler: [jQuery click events firing multiple times](http://stackoverflow.com/questions/14969960/jquery-click-events-firing-multiple-times?rq=1) – Yogi Feb 08 '16 at 13:48
  • I tried using unbind and the solution, but it still crashes in mobile web! – Jagrut Feb 08 '16 at 17:39

1 Answers1

2

You have some recursion going on which is exponentially adding #child .click() handlers. I have made this jsFiddle to simplify your code and demo what's going on. Open the console, click 'submit' to start, then click a few times on one of the list items. You'll see for each click, the console outputs more and more lines.

Try moving $("#child").on("click"...){} outside of function showAllData(){}

Update: So that the handler works after you remove and re-add #child you can add the click listener like this:

$('#parent').on('click', '#child', function() {
    // 
});

I've put this in an updated jsFiddle.

Update 2: I saw that Flipster was not re-initialising after you refresh #child and came up with this:

Change $("#child").flipster(); to $("#parent").flipster();. Then after doing $('#child').remove() in showAllData():

// remove the flipster classes from #parent or flipster will not re-initialise when called next time.
$('#parent').removeClass('flipster').removeClass(function(index, css) {
    return (css.match(/(^|\s)flipster-\S+/g) || []).join(' ');
});

I put this in a codePen.

Lesley
  • 1,395
  • 12
  • 11
  • If I do that, it works well for the first time, but after my ajax calls, the event is not fired. – Jagrut Feb 08 '16 at 13:36
  • Yes, I see the problem ... good catch. Yet, why is the click handler added in showAllData() triggered immediately? That is not obvious to me. – Yogi Feb 08 '16 at 13:40
  • If I do what is suggested in this answer, its not triggered immediately. It is triggered when I click on the element. But after one ajax call, it is not fired anymore. – Jagrut Feb 08 '16 at 13:42
  • I may have simplified one step to far in the jsFiddle, by ignoring your remove/add of `#child`. I've updated the [jsFiddle](https://jsfiddle.net/t6gfohjp/3/) and now when you click a list item, you can see it's calling `showAllData()` twice - once for the item click and once for the submit click... because you have _appended_ `#child` to `#submit`. Try using the `.after()` method instead: `$('#parent').after($('
    '));`
    – Lesley Feb 08 '16 at 13:48
  • I do not know why but the event is not triggered after first time! – Jagrut Feb 08 '16 at 17:40
  • @Jagrut can you make a [minimal, working example](https://stackoverflow.com/help/mcve) of your current code on jsFiddle or codePen? – Lesley Feb 08 '16 at 17:51
  • 1
    @Lesley I figured it out! The problem was with the plugin I was using. It was not unbinding the events even after I removed the elements it was applied on and even after I manually turn `off` all the events on that item. Do not know why was that happening. Maybe I need to look deeper in the plugin code. But for now, I settled with other plugin. Thanks a lot for your help. It did point me in the right direction! – Jagrut Feb 09 '16 at 18:03
  • @Jagrut Great! I was wondering whether it might be something to do with Flipster. I'm going to update my answer with another suggestion if you'd like to try - it might help if you wanted to stick with the Flipster plugin. – Lesley Feb 09 '16 at 18:40
  • @Lesley Wow! Thanks for all the effort. It Worked! :) – Jagrut Feb 10 '16 at 13:37