"Too Much Recursion" Problem - jquery-ui

I'm helping a company develop a website that utilizes jquery but I have noticed that the site slows to a complete halt with a jquery "Too Much Recursion" error. The company really needs to get this resolved but retain the slideshow capabilities as they are right now. Here is the code in question:
<script type="text/javascript">
var $testimonialCont;
var $slideshowContainer;
$(document).ready(function(){
$slideshowContainer = $('.slideshowContainer');
var inititalSlideshowDelay = setTimeout(cycle_slideshow_image, 4000);
$testimonialCont = $('.testimonialContainer');
$('.testimonialBubble').hide();
$('.testimonialBubble').removeClass('hide');
cycle_top_bubble()
var initialTestimonialDelay = setTimeout(cycle_top_bubble, 3000);
});
function cycle_slideshow_image(){
//This code cycles the slideshow caption headings and body text
$('h1.slideshowCaptionHeading:last').fadeOut(1500, function(){
$(this).prependTo('.captionHeaderArea');
$(this).show(1);
var delay = setTimeout(cycle_slideshow_image, 4000);
});
$('p.slideshowCaptionBody:last').fadeOut(1500, function(){
$(this).prependTo('.captionBodyArea');
$(this).show(1);
var delay = setTimeout(cycle_slideshow_image, 4000);
});
$('img.slideshowSlide:last').fadeOut(1500, function(){
$(this).prependTo($slideshowContainer);
$(this).show(1);
var delay = setTimeout(cycle_slideshow_image, 4000);
});
}
function cycle_top_bubble(){
$('.testimonialBubble:last').prependTo($testimonialCont).fadeIn(1500, function(){
var $this = $(this);
var thisTimer = setTimeout(function(){
$this.fadeOut(1500, function(){
var thisDelay = setTimeout(cycle_top_bubble, 3000);
})
}, 5000);
});
}
</script>
Here is the site's address: http://dbunderdevelopment.com/CRR/
If anyone has any suggestions, I would greatly appreciate it.
P.S. I did post this question before as an unregistered user and I sincerely apologize in advance for that. I can't seem to find the post in order to delete but, rest assured, it will not happen again. I know how bad repostings are on forums.

To me it looks like cycle_slideshow_image calls itself three times each time it is called... change it to this:
function cycle_slideshow_image(){
//This code cycles the slideshow caption headings and body text
$('h1.slideshowCaptionHeading:last').fadeOut(1500, function(){
$(this).prependTo('.captionHeaderArea');
$(this).show(1);
});
$('p.slideshowCaptionBody:last').fadeOut(1500, function(){
$(this).prependTo('.captionBodyArea');
$(this).show(1);
});
$('img.slideshowSlide:last').fadeOut(1500, function(){
$(this).prependTo($slideshowContainer);
$(this).show(1);
var delay = setTimeout(cycle_slideshow_image, 4000);
});
}
Also, cycle_top_bubble is being called twice initially, so it's running in two loops. remove this line:
var initialTestimonialDelay = setTimeout(cycle_top_bubble, 3000);
Another thing to consider is that when your page becomes an inactive tab in the browser, the timeouts are clamped to 1000ms (ref) so the animation may build up if you have the timeouts too short, which you don't, but it's something to keep in mind.

So you need to think about how recursion works, when you recurse in those set timeout functions you create a new scope inside the recursed function, Adding everything onto the stack without popping off the last function.
If you look at this as it is a block of memory but you never recurse which is the returning back up you continue to flood memory with more and more objects until its full. How you can solve this is pretty easy.
First recursion is the wrong approach for something that never completes, I explained why above. The recursion needs to be changed. The solution I would use is have a callback on the setTimeout but move your setTimeouts outside the scope of the calling function. This should help with the memory problem.
Other suggestions is to use a real slideshow plugin that someone else wrote... I know this may be frowned upon but why recreate the wheel when it has been done 1000 times. I recommend jQuery Cycle it is extremely fast and customizable.
Good luck!

Related

How to free up memory from Puppeteer in infinite scroll?

I browse an infinite scroll page using Puppeteer but this page is really really long. The problem is that the memory used by Puppeteer grows way too much and after a while, it crashes. I was wondering if there is a nice way to somehow free up memory during the scroll.
For example, would it be possible to pause every minute to remove the HTML that has been loaded so far and copy it to the hard disk? That way, after I'm done scrolling, I have all the HTML in a file and can easily work with it. Is it possible to do that? If yes, how? If no, what would be a viable solution?
I would wager that the approach you outline would work. The trick will be to remove nodes from only the list that is being added to. The implementation would maybe look something like this:
await page.addScriptTag({ url: "https://code.jquery.com/jquery-3.2.1.min.js" });
const scrapedData = [];
while (true) {
const newData = await page.evaluate(async () => {
const listElm = $(".some-list");
const tempData = listElm.toArray().map(elm => {
//Get data...
});
listElm
.children()
.slice(20)
.remove();
//TODO: Scroll and wait for new content...
return tempData;
});
scrapedData.push(...newData)
if(someCondition){
break;
}
}

Issue with mobile.loading and timing - JQuery Mobile

I am trying to show the loading animation during a function call that takes some time. The function call is searching a large array that is already loaded. After the search, matching items are inserted into a table. The table is cleared prior to starting the search.
The problem is the animation only displays during the brief moment when the page updates.
Here is my code:
var interval = setInterval(function ()
{
$.mobile.loading('show');
clearInterval(interval);
}, 1);
DoSearch(term, function ()
{
var interval = setInterval(function ()
{
$.mobile.loading('hide');
clearInterval(interval);
}, 1000);
});
//The search function looks like this (detail omitted for brevity):
function DoSearch(term)
{
$("table#tableICD tbody").html('');
// also tried:
/*$("table#tableICD tbody")
.html('')
.table()
.closest("table#tableICD")
.table("refresh")
.trigger("create");*/
var tr = '';
$.each(codes, function (key, value)
{
// determine which items match and add them as table rows to 'tr'
});
$("table#tableICD tbody")
.append(tr)
.closest("table#tableICD")
.table("refresh")
.trigger("create");
callback();
}
The search works properly and adds the rows to the table. I have two unexpected behaviors:
The table does not clear until the search is complete. I have tried adding .table("refresh").trigger("create") to the line where I set the tbody html to an empty string. This does not help. (see commented line in the code)
As I mentioned, the animation displays briefly while the screen is refreshing. (Notice I set the interval to 1000 in the second setInterval function just so I could even see it.)
The suggestions I have read so far are to use setInterval instead of straight calling $.mobile.loading, which I have done and placing the search in a function and using a callback, which I have also done.
Any ideas?
Let me give you a few suggestions; they will probably not solve all your issues but they may help you found a solution.
jQuery Mobile is buggy, and for some features, we will never know were they intended to work like that or are they just plain bugs
You can call $.mobile.loading('show') on its own only in pageshow jQuery Mobile event. In any other case, you need to do it in interval or timeout.
It is better to do it in timeout, mostly because you are using less code. Here an example I made several years ago: http://jsfiddle.net/Gajotres/Zr7Gf/
$(document).on('pagebeforecreate', '[data-role="page"]', function(){
setTimeout(function(){
$.mobile.loading('show');
},1);
});
$(document).on('pageshow', '[data-role="page"]', function(){
// You do not need timeout for pageshow. I'm using it so you can see loader is actualy working
setTimeout(function(){
$.mobile.loading('hide');
},300);
});
It's difficult to enhance any jQuery Markup in real time after a page was loaded. So my advice is to first generate new table content, then clean it, and then update markup using .table("refresh").
Do table refresh only once, never do it several times in the row. It is very resourced heavy method and it will last a very long time if you run it for every row
If you are searching on keypress in the input box then showing it in the table; that is the least efficient method in jQuery Mobile. jQM is that slow, it is much better to use listview component which is least resource extensive.

cancelling 1 interval on pageChange

I have 2 pages that require a function to be called every minute so I did this using setInterval(). However whenever I navigate to the page a new interval is created and it eventually bogs down the site. Is there a way to cancel an interval whenever I navigate away from a page?
var pollinginterval = 60000;
$('#HomeViewPage_MyLocation').live('pagebeforeshow', function(toPage, fromPage){
GetUsersByLocation();
setInterval(function() {
GetUsersByLocation();
}, pollinginterval);
});
$('#HomeViewPage_ColleagueLocation').live('pageshow', function(toPage, fromPage){
GetAllUsersByTeam();
GetAvailableTeams();
setInterval(function() {
GetAllUsersByTeam();
GetAvailableTeams();
}, pollinginterval);
});
Do you mean when refreshing the browser page? Then you can stop it by listenting for unload:
var runMyFunction = function() {
// clear interval
};
window.onunload = runMyFunction();
If not, you can still clear the interval on your internal page change.
This is because jQM has a problem with multiple events. Ok it is not a problem, you must understand, in your case, each time you access your page same event is applied again.
You can do 2 things to solve this problem:
Instead of live use bind/unbind and on/off to unbind event before binding it again to same element after each pagebeforeshow/pageshow. This is not that good approach.
Example for click event:
$('#elementID').unbind();
$('#elementID').bind('click', function(e) {
});
Correct one would be to use Event filter to check if event is already bound. It can be found here: http://www.codenothing.com/archives/2009/event-filter/
Example for click event:
$('#elementID:Event(click)').each(function(){
});

Jquery Mobile pagecreate function never completes

I am using the pagecreate initialization event to call a function which makes an AJAX call to populate a list.
The problem I have is that this event never completes. The page loading message persists.
I've search here and on the Jquery forum, without any luck.
My code looks like this:
$( "#events" ).live( 'pagecreate', function(event) {
// Executed once the page is loaded
var fromDate = new Date(),
toDate = new Date(fromDate.getFullYear(), fromDate.getMonth() + 3, fromDate.getDate());
update(fromDate, toDate);
//alert('done');
});
function update(from, to) {
var eventList = $('ul#event-list');
$.ajax({
url: 'events.php',
dataType: 'json',
data: {from: from, to: to},
success: function(data) {
showEvents(data, from, to, eventList); // Create list items and append to eventList
$('.value h2').formatCurrency({ negativeFormat: "-%s%n" }); // Format currency correctly using jQuery plugin
}
});
}
I get an "a.Deferred is not a function" error, which suggests to me it has something to do with the completion of the AJAX call, but I've checked, and the showEvents function is correctly creating the list items, so it's not hanging.
After reading this, I tried alternative initialization events: pageinit, and even changePage, without success.
Thanks for your help.
p.s. in case it helps, uncommenting that alert() gets the updated list to reformat correctly, without solving the problem. I figure I'd mention it, since I obviously don't understand what's going on.
If u want to run
the code only once when your project loaded then use
mobileinit. pageshow for every view of page and pagecreate for first
time when pagecreate in your project.

Ajax queue Backbone js

I am running Backbone js 0.9.2 on Rails 3.2.2,I have a page for adding cost rows.A cost have 3 TextFields: title, description and price.
I am saving each cost on blur.
model.save() gets called multiple times with very short intervals. Which issues one create(post) request then one update(put) request shortly there after. The problem I am experiencing is that PUT request sometimes reaches the server before the POST, the result being that model gets created and persisted twice(duplicates).
To save on blur is the requested behavior, so I need a way to queue up requests.
I have read something about Spine js, and that they solve it by some kind of queue. I've also looked in to this, but can't seem to figure this out.
It feels like this should be a common issue, working with "single-page-apps" but can't find anything about it.
You could override the save method and create a queue with a deferred object . For example,
var MDef = Backbone.Model.extend({
url: "/echo/json/?delay=3",
initialize: function() {
this.queue = $.Deferred();
this.queue.resolve();
},
save: function(attrs,options) {
var m = this;
console.log("set "+JSON.stringify(attrs));
// this.queue = this.queue.pipe with jquery<1.8
this.queue = this.queue.then(function() {
console.log("request "+JSON.stringify(attrs));
return Backbone.Model.prototype.save.call(m, attrs, options);
});
}
});
var m = new MDef();
m.save({title: "a title"});
m.save({description: "a description"});
m.save({price: "a price"});
And a Fiddle : http://jsfiddle.net/nikoshr/8nEUm/
User debounce from underscore.js.
Creates and returns a new debounced version of the passed function that will postpone its execution until after wait milliseconds have elapsed since the last time it was invoked.
This way it will only fire once after the last blur event.

Resources