JavaScript heap size ever increasing with AJAX calls - javascript

I am designing a web application, and the app requires that I use AJAX to navigate pages, so the same frame is static, but the inner content changes, like
$(".nav > div").on('click',function(){
var id = $(this).attr('id');
$(".active").removeClass("active");
$(this).addClass("active");
$("#main").load("/page" + id + ".html");
});
which will load page1.html, following me clicking on the element with the id '1', for example.
I then use
$(document).ajaxComplete(function() {...javascript...});
to run the rest of my script which will be interacting with the inner content. My script contains numerous functions like
$('#fade').on('click', function() {
$('#zoom').removeClass('grow').addClass('shrink');
which interact with unqiue id's, all of which are similar in each of the '/page[number].html' files.
My script runs fine if I run it on an entirely static page, but as soon as I start introducing the AJAX element of reloading the html in the inner frame, the website gets slower and slower every time I make an AJAX call - by using the .nav bar - until a crash. The javascript heap size seems to increase almost exponentially, see:
http://imgur.com/0mvoOjA
Not only the js heap size is ever increasing, but it also seems 'paint' is taking up a lot of memory. Each page I am loading a new, fairly high res image, could this be related?
I am fairly new to AJAX calls so any pointers would be appreciated! Thanks

It's likely that you're creating event handlers with $().on on the other pages and you aren't explicitly removing them before you navigate to another page.
$(element).on(event, function() {
// ...
});
When you make an event listener like this jQuery maintains a reference to the function, meaning it can't be garbage collected. Every time you navigate to a new page, you create more event handlers that can't be automatically removed.
function eventHandler() {
// ...
}
// when the page is loaded
$(element).on(event, eventHandler);
// just before you leave
$(element).off(event, eventHandler);
Better still, when you know there only needs to be one interaction with the element before you'll navigate away, you can use one, to create an event listener that will be called only once before it is automatically dereferenced.
$(element).one(event, eventHandler);
// don't worry about removing these handlers
How you structure this code is best determined by your existing application architecture.

You need to unbind the events. If not, you are binding and binding events to your element instead of override it. You can do it with $('#yourElement').unbind('click');

Related

On load instead of document ready with other javascript on page?

I currently have this bit of code going that looks for a certain class and adds the QTY text inside the class. I have to do it this way as I don't have access to the base HTML code for this portion of the site, but rather can do so via JS access.
The current code I have running is as follows:
$('.cart-product-qty').each(function() {
$(this).prepend("QTY: ");
});
But the problem I just ran into is when certain functions are performed in the shopping cart it doesn't refresh, so it ends up dropping the QTY text. Is there another method so that it keeps it there continuously even if the page "refreshes"?
Listen to the parent div underneath the products will be listed. So whenever the content changes, you can trigger your function.
DOMSubtreeModified event might be helpful.
var element = document.getElementById('div');
element.addEventListener('DOMSubtreeModified', updateQtyText);
function updateQtyText(e) {
$('.cart-product-qty').each(function() {
$(this).prepend("QTY: ");
});
}
Reference : fire a call when inner HTML changes.
This might help

Cloning Objects in Google Optimize

I'm trying to clone a button in Google Optimize (or any other javascript/jQuery method) that adds an item into a shopping cart. My problem is that when I run the code or experiment in Optimize, the button doesn't trigger.
Here's my two different attempts. Method 1 via Optimizes' interface.
Select the button to copy, use the 'edit code' to get the html.
Use Insert HTML a the location of the new button, and insert the code.
Version 2 uses jQuery's clone();
$('#SOME-ID > PATH TO THE ELEMENT TO CLONE').clone().attr('id', 'ADD-ID-FOR-GTM-TRACKING').appendTo('#proPriceMobile');
What could the problem be?
Thanks in advance!
It's quite possible, that your experiment fires BEFORE your buttons loads on your page, in your actual browser.
Do you get an error message in console?
My tip would be to wait for your button to load, before applying the DOM changes. If possible, do this all via JavaScript.
For example, here you can wait for an element to load, via using a callback and setTimeout():
// FUNCTION WHICH WAITS FOR YOUR INITAL BUTTON to LOAD
function waitForElement(className, callBack){
window.setTimeout(function(){
// GRAB YOUR ELEMENT
var element = document.querySelectorAll(className)[0];
if(element) {
callBack(className, element);
console.log("Callback successfully fired and code executed...")
} else {
waitForElement(className, callBack);
console.log("This runs every second until your element is loaded on the page..")
}
},1000)
};
// EXECUTE THE CODE IN THIS FUNCTION, WHEN YOUR BUTTON LOADS IN THE DOM
waitForElement(".your-element-classname",function(){
console.log("Button has loaded in DOM...");
// NOW CLONE YOUR BUTTON
});
When I've cloned buttons in the past, I've lost all functionality on the cloned button. So you may need to rebuild that functionality on the cloned button.

Event "load" on iframe triggers successfully but iframe can't be targeted

I've successfully created a snippet of code that takes a CSV array and through an IFRAME drop the text into Wikipedia's search bar and click the search button. Unfortunately, after loading, I'm unable to target the IFRAME's content any longer. I've also nested two load event handlers with the intent to wait for each page to complete loading.
I have the handlers set to unbind/off after firing and that seems to prevent "duplicate events" from firing. I've tried a couple of tactics to determine if the event handler is triggering at the right time along with changing the target ID but not certain what else to try at this point. I suspect the 2nd event handler is triggering while on the previous page since it already triggered ready but the "appends" seem to work as expected.
$("#debugwindow").append("pre<br>");
$("#iframeTarget").on("load", function() {
$("#iframeTarget").unbind();
$("#iframeTarget").off();
$("#iframeTarget").attr("id","iframeTarget2");
$("#debugwindow").append("start interior of 1<br>");
$("#iframeTarget2").on("load", function() {
$("#iframeTarget2").unbind();
$("#iframeTarget2").off();
$("#iframeTarget2").attr("id","iframeTarget3");
$("#debugwindow").append("start interior of 2<br>");
$("#iframeTarget3").contents().find("#searchInput").val("I don't work?"); // 3 fails?
$("#iframeTarget,#iframeTarget2,#iframeTarget3").html("even I don't do anything!"); // fails?
// $("#iframecont").html("I ruin everything!"); // targets iframe container as test
$("#debugwindow").append("end interior of 2<br>");
});
$(this).contents().find("#searchInput").val("3M"); // 1 successfully fills search
$(this).contents().find("#searchButton").trigger("click"); // 2 successfully triggers button, changes URL to 3M page
$("#debugwindow").append("end interior of 1<br>");
});
$("#debugwindow").append("post<br>");
Looking for any insights into properly setting up the 2 event handlers or if my logic is wrong. Ideally, I will be able to fill the search bar, trigger the search, and then manipulate the DOM on the next loaded page.
This is because of security concerns in the browser. You will not be able to execute any script in the javascript iframe, as it exposes extreme risk if you're able to execute javascript code inside a remote iframe.
For example:
<iframe src="http://website.to.hack"></iframe>
$(iframe).load(() => {
$.ajax({
url: 'http://my.website',
data: iframe.document.cookie
});
});
Now I have all your cookies for that site. Unless that frame has a specific trust between your site and it, you're not going to be able to script. (You'll likely need a chrome extension for that).
See this post and thread for more information.

Callback after PJAX request is finished and has downloaded assets

An application of mine uses PJAX style navigation, which means that rather than loading the full page, we use AJAX to load a partial page and then use the HTML5 history/pushState API to update the browsing history.
Previously I was using the window.onload event to measure end user page loading times and I want to be able to record these times with the PJAX page loads, the problem is that this event does not fire after PJAX loads.
I have access to a pjax:end event which fires once the PJAX request is complete, but this is fired before all assets have finished downloading. I would like to be able to instrument the complete time it takes to download the page including the time to download extra (images/scripts) assets.
Is this possible? Is there a callback i'm missing or some magic that will allow me to measure the complete request time?
I realised that I only need to wait for images (not scripts).
A friend pointed me to this jQuery plugin: https://github.com/alexanderdickson/waitForImages
I'm using this code to trigger the onload event:
$('#main-inner').waitForImages(function() {
window.onload();
});
I don't think there is a specific event for a block of HTML loaded asyncronously. I think the best option is to attach your html, find each img and script, then bind to the load event (assuming jQuery) for each of them. When the number of loads equals the number of elements you found, then everything is loaded. I hope this helps.
var start = new Date().getTime(),
elems = $('#my-div').append(html).find('img, script'),
count = 0;
elems.on('load', function () {
if (++count === elems.length) {
var diff = new Date().getTime() - start;
}
});

Check if the webpage has been modified

I am working on chrome extension for facebook. If you use facebook, you know that when you scroll down to the bottom of the news feed/timeline/profile it shows more posts. The extension actually adds a button beside the "like" button. So I need to check if there are more posts to add that button to.
Right now to check if the page has been modified, I use setInterval(function(){},2000).
I want to run a function when the user clicks the button. But this function doesn't work if I put it outside (or even inside) setInterval() – The Koder just now edit
How can I check if the webpage has been modified WITHOUT using a loop?
Example:
$(document).ready(function(){
window.setInterval(function(){
$(".UIActionLinks").find(".dot").css('display','none');
$(".UIActionLinks").find(".taheles_link").css('display','none');
$(".miniActionList").find(".dot").css('display','none');
$(".miniActionList").find(".taheles_link").css('display','none');
//only this function doesn't work:
$(".taheles_link").click(function(){
$(".taheles_default_message").hide();
$(".taheles_saving_message").show();
});
//end
$(".like_link").after('<span class="dot"> · </span><button class="taheles_link stat_elem as_link" title="תגיד תכל´ס" type="submit" name="taheles" onclick="apply_taheles()" data-ft="{"tn":">","type":22}"><span class="taheles_default_message">תכל´ס</span><span class="taheles_saving_message">לא תכלס</span></button>');
$(".taheles_saving_message").hide();
}, 2000);
});
In the future, this extension will use AJAX, so setInterval() can make even more problems for me.
If I understand correctly you want to get a notification when the page's DOM changes. And you want to do this without using the setInterval() function.
As your problem lies within the attaching event handlers to elements that are created after the page has loaded, you might be interested in checking out the jquery.live event attachment technique. I think it will solve your issue.
In general you want the page to throw a mutation event. There is a mutation event spec that might be what you're looking for. Here are some links that might be useful.
http://tobiasz123.wordpress.com/2009/01/19/utilizing-mutation-events-for-automatic-and-persistent-event-attaching/
Detect element content changes with jQuery
$(document).ready(function(){
setInterval('fun()',5000);
fun();
});
function fun()
{
alert(11)
}

Categories