Website loses performance after some jQuery $.ajax calls - ajax

I admit I'm quite noob with full ajax websites, and so I'm surely making some mistakes.
The problem is this:
in http://lamovida.arabianessence.com
every page is loaded with an $.ajax call using this function
function getAjaxPage() {
$('a.ajaxc').click(function() {
$("li.page_block").find(".wrapper").fadeOut(400).remove();
hideSplash();
var $thishref = $(this).attr('href'),
$thisurl = $thishref.replace("#!/",""),
$urlArr = $thisurl.split('-'),
$urlOk = $urlArr[0],
$dataOk = $urlArr[1];
$.ajax({
url : $urlOk + ".php",
data : 'id='+$dataOk,
success : function (data,stato) {
$("#content").css({opacity:1}).fadeIn(400);
$("li.page_block").html(data);
$("li.page_block").css('visibility', 'visible');
$("li.page_block").find(".wrapper").css({opacity:0}).show().animate({opacity:1},1000);
var $whgt = $(".wrapper").height(),
$ctop = ( ( $(window).height() - $whgt ) /2 )-40;
$("#content").stop().animate({height: $whgt+40, top: $ctop},1000);
$("li.page_block").css('padding-top',20);
$('.scrollable').jScrollPane();
$('.slider>ul>li').jScrollPane();
getAjaxPage();
},
error : function (richiesta,stato,errori) {
alert(errori);
}
});
});
}
Every time this function is called the content gets loader slower, and after about 20 clicks things get real bad, and the loading time grows and grows.
I tried to analyze the situation using the Google Chrome's Timeline, and I saw that after each click the browser uses more memory. If I comment the getAjaxPage(); row in the "success" section the situation starts to get better, but of course I lose all the internal navigation.
What could I do to avoid this problem?
Many thanks to all!

Every call to $('a.ajaxc').click() is adding new event handler thus every click causes more requests to be made. After the first click, every click will cause two requests. Another click? Another three requests. Etc.
Put the handler outside the function and you will have only one AJAX call per click:
$(document).ready(function() {
$('a.ajaxc').click(getAjaxPage);
});
I also don't see the reason behind calling getAjaxPage again from within the callback, so remove it as well to avoid infinite loop of requests.

Related

Handle ajax response with node.js

I am trying to scrape information from a specified website. This site uses authentication first, thus a i use zombie.js:
var Browser = require("zombie");
var browser = new Browser();
browser.visit("https://*****login.aspx", function(){
browser.fill('#user', '*****');
browser.fill('#pwd', '*****');
var button = browser.querySelector('#btnSubmit');
browser.fire('click', button, function(){
//scraping main.aspx
});
});
It's working, i can scrape the main.aspx: there is a <table>, containig information about new messages(from, date, subject,), the problems comes here: the subject field is clickable, and clicking on it makes a new window appear with the actual message. However it is an ajaxgrid, and when i perform a click:
var field = browser.querySelector('#VeryLongIdOfTheField');
browser.fire('click', field, function(){
console.log(browser.querySelector('#VeryLongIdOfTheFieldContainingTheMessage').innerHTML);
});
it returns an error message, saying that undefined has no innerHTML. I suppose its because this action handled with some ajax magic. I am new in this js/nodejs/jquery/.. world, some help needed to enlight me.
Since the data is populated using async ajax, I'm guessing there's a lag between your click and the actual DOM population inside the node. How about waiting for a bit before checking the content inside the node.
browser.fire('click', field, function(){
setTimeout(function(){
console.log(browser.querySelector('#VeryLongIdOfTheFieldContainingTheMessage').innerHTML);
}, 3000)
});
If the time taken is not very predictable, you could also run it inside a loop until you find the content or exit after a reasonable number of retries.

jQuery .load() wait till content is loaded

How to prevent jQuery $('body').load('something.php'); from changing any DOM till all the content from something.php (including images,js) is fully loaded
-Lets say some actual content is:
Hello world
And something.php content is:
image that loads for 10 seconds
20 js plugins
After firing .load() function nothing should happen, till images an js files are fully loaded, and THEN instantly change the content.
some preloader may appear, but its not subject of question.
[edit]----------------------------------------------------------------------
My solution for that was css code (css is loaded always before dom is build) that has cross-browser opacity 0.
.transparent{
-moz-opacity: 0.00;
opacity: 0.00;
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha"(Opacity=0);
filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0);
filter:alpha(opacity=0);
}
And it prevent from bad flickr of content usually but not always. Now its possible to detect somehow that content is loaded by jQuery ajax and apply some show timeout and so on. But in fact question is still open.
To make now a little more simple example for that question:
How to begin changing DOM after $('body').load('something.php') with 3000ms delay after clicking the link that fire .load('something.php') function? (Browser should start downloading instantly, but DOM changing has to be initiated later)
Use .get instead and assign the contents in the success callback:
$.get('something.php', function(result) {
$('body').html(result);
});
There are some implementation details you may have to solve yourself, but here's a rough solution:
Don't use .load() directly. It can't be changed to wait for all images to load.
Use $.get() to fetch the HTML into a variable, let's call it frag.
Use $(frag).find('img').each(fn) to find all images and dump each this.src inside a preloader.
var images = [],
$frag = $(frag),
loaded = 0;
function imageLoaded()
{
++loaded;
// reference images array here to keep it alive
if (images.ready && loaded >= images.length) {
// add $frag to the DOM
$frag.appendTo('#container');
}
}
$frag.find('img').each(function() {
var i = new Image();
i.onload = i.onerror = imageLoaded;
i.src = this.src;
images[images.length] = i;
});
// signal that images contains all image objects that we wish to monitor
images.ready = true;
Demo
Once all images are loaded, append the earlier frag to the DOM using $frag.appendTo('#container').
Here is a quick proof of concept that loads relevant images before inserting an HTML fragment into the DOM: http://jsfiddle.net/B8B6u/5/
You can preload the images using the onload handler to trigger iterations:
var images = $(frag).find('img'),
loader = $('<img/>');
function iterate(i, callback) {
if (i > 0) {
i--;
loader.unbind("load");
loader.load(function() {
iterate(i, callback);
});
loader.attr('src', images[i].src);
}else{
callback();
}
}
iterate(images.length,function(){
$('#container').html(frag);
});
This should work, since each image is loaded after the previous one has finished loading.
Have you tried this?
$(function(){$('body').load('something.php')});
Edit: I just realized you are actually wanting to wait for the stuff to load before it get's placed in the body.
Here are three links to similar questions.
Preloading images with jQuery
Is it possible to preload page contents with ajax/jquery technique?
Preloading images using PHP and jQuery - Comma seperated array?
You can probably adapt those to scripts too.
This might work too.
$.ajax({
'url': 'content.php',
'dataType': 'text',
'success': function(data){
var docfrag = document.createDocumentFragment();
var tmp = document.createElement('div'), child;
//get str from data here like: str data.str
tmp.innerHTML = str;
while(child = tmp.firstChild){
docfrag.appendChild(child);
}
$('body').append(docfrag);
}
});
It's a longer way of doing what Shadow Wizard suggests, but it will probably work.
Hm. Never mind. Jack's answer looks the best. I'll wait a while and if no one likes my answer I'll delete it.
Edit: It looks like appending to documentfragments can do http requests.
Any script using createDocumentFrament may benefit from preloading.
In this question they want no http requests even though that's what createDocumentFragment is doing:
Using documentFragment to parse HTML without sending HTTP requests.
I can't be sure if this is true for all browsers or just when the console.log is run, but it could be a good option for preloading if this behavior is universal.

Using Form Validation submitHandler to send 2 AJAX requests?

I've got a pretty strong understanding of php, html & css but i've only just started to dive into javascript & jQuery.
The problem i'm facing is that I have a form on a page that I want first to validate, then when it passes validation to submit 2 ajax requests; the first to insert data into a table in my database and the second to run a query on another table and return the result.
I've got the latter working just fine using the submitHandler method to send the ajax request and update a div on my page with it's result. When I added a second ajax call after or before this one it seems to break...
My question is should there be a problem with having 2 ajax calls in the submitHandler, like below, and if so what would be the correct way to go about this, or even a better way?
$("#contactform").validate({
rules: ...
submitHandler: function() {
// First to insert the contact details using input#firstname etc.
var firstname = $("#firstname").value();
var lastname = $("#lastname").value();
var contactString = 'firstname='+ firstname + '&lastname=' + lastname;
$.ajax({
type: "POST",
url: "insertcontact.php",
data: quoteString,
success: function(server_response){
$('#yourquote').html(server_response).show();
}
});
// Second use width & height submitted from previous page for processquote.php
var width = <?php echo json_encode($cleanpost['width']); ?>;
var height = <?php echo json_encode($cleanpost['height']); ?>;
var quoteString = 'width='+ width + '&height=' + height;
$.ajax({
type: "POST",
url: "processquote.php",
data: quoteString,
success: function(server_response){
$('#yourquote').html(server_response).show();
}
});
}
});
I'm using the 'jquery.validate.js' validation plugin. Again my goal is such that once someone has entered valid details on my form, using Ajax their contact data is inserted into the database then the database is queried using fields submitted on the previous page to retrieve a numerical result to display on the page, without a refresh.
Any pointers you could give me would be much appreciated!
Rob
EDIT: Learning Javascript & Jquery simultaneously isn't such a good idea it seems, i've confused: this.value = ''; with $(this).val(''); as shown in the first 2 variable declarations, this is what was causing problems! Thanks for your useful help anyway guys, will upboat for your assistance.
In your first .ajax() call, you are trying to pass it a value in the data: parameter that you have not created yet. I believe you are wanting to send it the contactString instead.
Unless your two queries depend on each other being done sequentially then you should be able to execute them both asynchronously (essentially at the same moment). If you want the second AJAX call to happen after the first one, you could always pass all of your data parameters to insertcontact.php and once the insertion is done, execute processquote.php with the values you already passed through.
Lastly, I wonder if you are meaning to do this, but both of your AJAX calls overwrite whatever is in the #yourquote DOM element and show it. You might want to provide a separate element to put the response in for each of your two requests. Perhaps #yourquoteinserted and #yourquoteprocessed?
Edit: BigRob, from your comment it sounds as if you want to make synchronous AJAX queries, check out the async property of your .ajax() call. This is from the .ajax() documentation:
async Boolean
Default: true
By default, all requests are sent asynchronously (i.e. this is set to true by default). If you need synchronous requests, set this option to false. Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation. Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active.
(emphasis mine)
However, I could be wrong about this but you might actually be able to call one asynchronous AJAX method from within the success function of another. If it starts looking too intermingled for you, you might want to extract the inner call into a function. Rough approximation of what it might look like:
$.ajax({url, data:contactString,
success: function(server_response) {
extractedId = server_response; // you can return data many ways
$.ajax({url2, data:quoteString+"&extra="+extractedId,...
});
}
});
If you perform a synchronous call by setting async:false in the first AJAX call, then you could just store the result into an external (to the AJAX call) variable (or if that doesn't work store it in some DOM element temporarily). Then the javascript will pause execution and won't fire your second AJAX call until the first one has returned.
This is all hypothetical for now, though, and just based off of my understanding of how it should work.

Ajax.BeginForm switches from async to sync

I'm running into an issue with an async call to the server that only works one time, then it appears to become a synchronous call. Let me try to explain.
It's an MVC 2.0 site, using ASP.NET and Ajax. I'm using the Ajax.BeginForm helper, like so:
<% using (Ajax.BeginForm("Start", null,
new { virtualMachineId = xyz },
new AjaxOptions { UpdateTargetId = "VirtualMachineForm", OnBegin="OnStartingVm" }
)){
Then while the machine is starting I want to call back to the server and get an update every second. It works the first time correctly, then changes behavior. OnStartingVm looks something like this:
function OnStartingVm() {
$('#StartingDiv').css('visibility', 'visible');
$('#StartingDiv').show();
var vmId = xyz;
intervalId = setInterval(function () {
updateStartingStatus(vmId)
}, 1000);
}
function updateStartingStatus(vmId) {
/* This part always runs */
$.ajax({
url: "/member/vm/getstartingstatus/" + vmId,
dataType: 'json',
async: true,
success: function (data) {
alert('This part runs every second on the first time only');
if (data.status == "Running") {
$('#StartingDiv').text(data.percentComplete);
}
else {
$('#StartingDiv').css('visibility', 'hidden');
$('#StartingDiv').hide();
clearInterval(intervalId);
}
},
});
}
Within the updateStartingStatus function, the first part runs every second, every time. However, within the Ajax call, the success result works every second on the first time only. Then on the second time I click on the start button all of the requests queue up. After the starting has completed, about 20 seconds later, I get a bunch of alert windows back to back. So, I can tell that updateStartingStatus runs every second every time, but the ajax call appears to switch to become a sync call after the first time.
Refreshing the browser window doesn't help. I have to fully close it and open it again. The same occurs in IE and Chrome.
One more thing to note is that the updated div (VirtualMachineForm) contains most of the page, including the button being pressed. So it basically replaces the page from under itself. Not sure if that would cause any issues.
Additionally, if I debug in Visual Studio 2010, the call isn't made to the controller action when the issue occurs. So, it appears to be something client-side. I've ruled out any issues server-side.
I eventually figured it out. This post lead to the answer.
It was session state related and the browser locked the request until a previous one was completed. I didn't need to disable session state, but I had to avoid a session write from code.
That explains why a browser refresh didn't work and why I had to close and open the browser again.
Why don't you call clearInterval function?

Assign jQuery.get() to a variable?

What is the correct way of assigning to a variable the response from jQuery.get() ?
var data = jQuery.get("output.csv");
I was reading that jQuery.get() must have a callback function? why is that? and how would i use this callback function to assign the response back to the data variable?
Thanks in advance for your help and clarification.
Update:
Thank you all for your answers and explanations. I think i am starting to finally grasp what you are all saying.
My code below is doing the right thing only the first iteration of it.
The rest of the iterations its writing to the page undefined.
Am i missing something?
<tbody>
<table id="myTable">
<script type="text/javascript">
$.get('output.csv', function(data) {
csvFile = jQuery.csv()(data);
for ( var x = 0; x < csvFile.length; x++ ) {
str = "<tr>";
for ( var y = 0; y < csvFile.length; y++) {
str += "<td>" + csvFile[y][y] + "</td>";
}
str += "</tr>";
}
$('#myTable').append(str);
});
</script>
</tbody>
</table>
A callback function is required for asynchronous function calls, like an AJAX GET request. There is a delay between calling the get function and getting a response back, which could be a millisecond or several minutes, so you need to have a callback function that gets called when the asynchronous GET has completed its work.
Here's some more info on jQuery's AJAX get function: http://docs.jquery.com/Ajax/jQuery.get#urldatacallbacktype.
From jQuery's examples:
// this would call the get function and just
// move on, doing nothing with the results
$.get("test.php");
// this would return the results of the get
$.get("test.php", function(data){
alert("Data Loaded: " + data);
});
If you get undefined when you try to use the data variable in the callback function, open up the console in Firebug in Firefox and watch the get request. You can see the raw request and the response that it comes back with. You should get a better indication of the issue after seeing what's being sent to the server and what's being sent back to the client.
tsvanharen answered the question well, but DCrawmer's still missing the point. Let me attempt a clarification for him. I'm oversimplifying some of this, and smoothing over some details.
Look at the code shown below. This is pretty much the same code as tsvanharen's, except that I've replaced the anonymous function for the callback with an actual function pointer, and am a little more explicit so you can see what's going on:
var x = null;
function myCallback(data)
{
alert("Data Loaded:" + data);
}
$.get("test.php", myCallback);
// the rest of your code
alert("The value of X is: " + x);
Assuming that test.php takes even a moment or two to load, notice the order that the alerts probably come up in:
1. "The value of X is"
2. "Data Loaded"
The function $.get() runs instantaneously. JavaScript moves on and runs the rest of your code right away. In the background, it's retrieving your page at test.php. jQuery hides some of the messy details of this.
The callback function (the second argument to $.get()) runs later (asynchronously). Or, said another way, the function myCallback is a handler to an event. That event is "$.get() has finished retrieving the data". It doesn't get run until that point. It doesn't run when $.get() runs! $.get() just remembers where that function is for later.
The function myCallback may run milliseconds or minutes later, long after $.get() has been dealt with.
If myCallback doesn't run until minutes later, then what's the value of x when the "The value of X" code is run? It's still null. There's your bug.
To use the data retrieved from the page in your script, you have to do things more like this:
Start your script, declare your variable to hold the data.
Call $.get(), with a callback function to handle the return.
Do nothing else. [Or, at least, nothing that requires the data]
Let the page just sit there.
...sometime in the future...
X. Your callback function will get run, and have the results of your web page.
Your callback function can:
* Display the data
* Assign that data to a variable
* Call other functions
* Go along it's merry way.
Actually in your example the data will be the XMLHttpRequest request object.
var x;
$.get( 'output.csv', function(data){
x = data;
console.log(x); // will give you the contents.
});
I really struggled with getting the results of jQuery ajax into my variables at the "document.ready" stage of events.
jQuery's ajax would load into my variables when a user triggered an "onchange" event of a select box after the page had already loaded, but the data would not feed the variables when the page first loaded.
I tried many, many, many different methods, but in the end, the answer I needed was at this stackoverflow page: JQuery - Storing ajax response into global variable
Thanks to contributor Charles Guilbert, I am able to get data into my variables, even when my page first loads.
Here's an example of the working script:
jQuery.extend
(
{
getValues: function(url)
{
var result = null;
$.ajax(
{
url: url,
type: 'get',
dataType: 'html',
async: false,
cache: false,
success: function(data)
{
result = data;
}
});
return result;
}
}
);
// Option List 1, when "Cats" is selected elsewhere
optList1_Cats += $.getValues("/MyData.aspx?iListNum=1&sVal=cats");
// Option List 1, when "Dogs" is selected elsewhere
optList1_Dogs += $.getValues("/MyData.aspx?iListNum=1&sVal=dogs");
// Option List 2, when "Cats" is selected elsewhere
optList2_Cats += $.getValues("/MyData.aspx?iListNum=2&sVal=cats");
// Option List 2, when "Dogs" is selected elsewhere
optList2_Dogs += $.getValues("/MyData.aspx?iListNum=2&sVal=dogs");
You just need to specify the callback function in the parameter to get method. Your data will be in the variable you specify in the function.
$.get("output.csv", function(data) {
// Put your function code here, the 'data' variable will hold your data.
});

Resources