Multiple clicks slows down the application performance - javascript

Before I explain the problem, I want to describe short what I am trying to achieve
I have made 5 diagrams and one NavigationList. The NavigationList consists of pure HTML that displays a list of table1, table2, table3, table4 and table5 (JavaScript files). The user will click on a specific row inside the list, then the table the user wants to view will be displayed, and he can only view one diagram once a time.
For instance: I the user wants too view diagram1, then he must click on diagram1. Later he wants to view diagram2, then diagram1 will be closed because he have clicked on diagram2.
The problem:
If the user clicks multiple times on the same list name (for instance diagram1), then each click will slow down the diagram, very strange. So if the user clicks 10 times, the diagram will slow down 10 times more. Why is this happening and how can I solve this problem?**
This is table2.js, I believe that $(document).ready(function() has something to do with why the diagram slows down after each click.
(function table2(){
$(document).ready(function() {
// table2 code content is taken away to save space in this file on stackoverflow...
});
}());
This is the part where I call the diagrams by using JQuery event with if statement.
$('[data-row]').on('click', function() {
var row = $(this).attr('data-row');
$('.active').removeClass('active');
$('#table' + row).addClass('active');
if(row == 1){
$.getScript("table1.js", function(){});
table1();
} else if (row == 2) {
$.getScript("table2.js", function(){});
table2();
} else if (row == 3) {
$.getScript("table3.js", function(){});
table3();
} else if (row == 4) {
$.getScript("table4.js", function(){});
table4();
}else if (row == 5) {
$.getScript("table5.js", function(){});
table5();
} else {
}
});
This is a statistic result that shows why the performance is so slow, as you can see; each table is receiving data samples. After multiple clicks the performance is high drops down from 40 fps to 6.5 fps, strange??
Click here to view the slow performance statistics

because each click you doing ajax request so if you click 10 times you making 10 requests plus calling table12(); functions which can be heavy.. you need to change your code to check if diagram is visible if yes dont do another request

You probably have a memory leak. Make sure you clean up global variables properly and DOM nodes properly. Your browser should have developer tools which should allow you to see memory usage.
I'm also a bit worried by this code:
$.getScript("SensorTables/ExhaustTemperature.js", function(){});
table1();
.getScript() is an asynchronous function, so table1() will be executed before the browser has loaded the script.
The correct code is probably:
$.getScript("table1.js", function(){});
since the function table1 is defined in such a way that it's executed right away. That means your code logs an error in the JavaScript console when you click the first time. When you click a second time, the function is called twice (once when jQuery fetches the script from the server and again from your code).
$(document).ready(); isn't necessary inside of (function table1(){}()); - when this code is executed, the DOM is ready. Maybe the code is there because other pages use the script as well. My recommendation would be to move that into the places where you need it.
Lastly, if you give the function a name, then the browser keeps it around. That may eat a lot of memory, depending on how complex the code is. If you want to keep the code around, this should be much faster:
if(table1) {
table1();
} else {
$.getScript("table1.js");
}
since it loads the script only once.
If you want to load the script again every time the user clicks and save memory:
$.getScript("table1.js");
and change the script to
(function (){
// table2 code content is taken away to save space in this file on stackoverflow...
}());
(i.e. remove the name of the function). The browser will then execute it once and forget as much as it can about it.

Related

Use javascript (and jQuery and other libs) from parent document on iframe with several sources

good day all.
I'm working on a project in which there is an application that has one of its view implemented with an iframe, the iframe src is changed when the user clicks on some of the "parent" document. So basically there is always the same container, but the contents of the iframe will change according to the user choices.
let's say that there will be:
parent.html (which will have all the js logic)
child1.html
child2.html
...
each "child" page will be an html page with no (or very little) javascript. What I want to obtain is that when the user arrive on the child1.html, only the code that is global to every child is execute and of course also the code related to that page.
Let's say that on the child1.html there must be executed a couple of ajax calls, then some js to handle tables, and things like that. while on the child2.html there will be some forms whith their own validations, and another ajax call to send the forms (displayed on the child1.html).
There will be a big js library on parent.html that will contain the js code of every child page, so what I'd like to have is a way to "know" in which page I am and execute only the portion of code that is related to that page.
the structure should be something like:
var myGlobalObject = {username:undefined,foo:1}
if(childpage1.html){
if (myGlobalObject.username == undefined){
$.ajax(retrieve username);
$("#someTableIniFrame",iframeContext).doSomething();
}
}
if(childpage2.html){
$("body",iframeContext2).on("submit","#someFormOnChild2", function(){
//do something
});
}
and/or something on childpages that could execute only its code... like:
document.addEventListener("DOMContentLoaded", function(event) {
//execute only my part of the global js!
});
I hope to have been clear on what I'd like to obtain:
a parent page, with all the js used in childs, executed on demand OR with the capability to understand in which page we are.
several child page without or with a very little js.
Just for information, the iframe src will be changed by js on the parent page, by destroying the previous one and adding a new iframe with the new source.
If you want to keep all the Javascript in the parent page then you just really need a way to map the child pages to any code you wish to execute. This is a long way around doing something, but without further context it's difficult to suggest a more appropriate solution.
With that in mind, here's how I'd approach your problem.
First of all, I'd create an array of objects that defines what script to run for each child page...
var childScripts = [{
"src": "childpage1.html",
"init": function() {
// what to do when childpage1 is loaded
}
},
{
"src": "childpage2.html",
"init": function() {
// what to do when childpage2 is loaded
}
}];
Don't destroy and recreate the iFrame every time you want to load a new page, or (if you really have to), assign an event handler to the load event every time. You only have to do this once if you never destroy the iFrame...
$("#iframeId").on("load", function() {
var scriptInfo = childScripts.filter(function(childInfo) {
return window.location.href.slice(-childInfo.src.length) === childInfo.src;
});
for (var i in scriptInfo) {
scriptInfo[i].init();
}
});
Obviously replace the selector #iframeId with something that will find your iframe.
In short, you create an array that holds each child page filename (prefix with / so you don't run scripts on pages that end with the same thing, but aren't the same page), and a function that you want to execute when that page loads. You then parse that array each time the iframe is loaded and execute all associated functions. Realistically you'll only have 1 init function per child page, but that code will handle multiple instances.

ERROR: 508 (Loop detected)

Well, this isn't like a proper question or anything..
I am just a bit curious, tried searching but couldn't find accurate answer for my problem so I had decided to try out and ask another question out here.
I have this small fun-time project in which you are supposed to keep on clicking a button until you gain the highest clicks among the other players, I have a page ManageClick.php which has the following code in it -
<?
sleep(rand(1,3));
$storage = fopen("TOTAL.txt", "r+");
if (flock($storage, LOCK_EX)) {
$a = fread($storage,filesize("TOTAL.txt"));
$a++;
fseek($storage, 0);
fwrite($storage, $a);
flock($storage, LOCK_UN);
} else {
}
fclose($storage);
?>
The above adds a random delay between 1-3 seconds and then opens a file TOTAL.txt reads it, and adds +1 to the value in the file.
I have a main page Testpage.html which has a simple button and a JQuery function which calls the page ManageClick.php when the button is clicked. However, now the problem arises. Whenever an user rapidly clicks the button in the main page it shows the following error in the Console window-
GET http://domain.tk/ManageClick.php 508 (Loop Detected)
GET http://domain.tk/TOTAL.txt 508 (Loop Detected)
WHERE domain is my website's name.
Any idea what could be causing the following issue? Rapid clicking of the button is one of them which I guess sends multiple requests to the page and causes the 508 error. Also, any possible way in which I could try and fix this error from showing up in the Console?
Also, please note that I am not English... Sorry for it.
PLEASE SEE- Adding the code of my Testpage.html for better quality of help.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
$(function(){
$("img").click(function() {
var test = $("#Clicks").load("TOTAL.txt");
$.post('ManageClick.php');
});
});
</script>
</head>
<body >
<center>
<img src='ABCD.png'>
<div id='Clicks' style=""></div>
</body>
</html>
If I understood, you have a webpage that has a game in which you call a php script to save how many times the user has clicked on a button.
You say the console (I guess chrome's developper tools or the similar) returns a 508 error as "Loop detected". This is the server telling the client that there might be a loop in the code because it gets called too many times. Well... it's not an automated redirect, it's just you calling it tons of times.
According to your explanation of the game, I would rather save the number of clicks in a javascript variable, and send them only after the game ended. This way, you only call the server one time.
On the other hand, your php code assumes that there's only one user of your website. I mean, you save the value in a file, but it doesn't take in account who's game is it.
Think that if you and I opened the website at the same time, you start adding clicks, and then I add another one, but the count gets saved in the same place.
Edit: Code example
jQuery:
var test = $("#Clicks").load("TOTAL.txt");
$("img").click(function() {
test = parseInt(test) + 1;
});
With this, you load the number previously stored and keep count of the clicks. Next you need to build a function that sends the click count after some idle time (or if you have a timeout per round )
I'll assume that if the user spent 3 seconds without clicking, he's gone, so I update the server. The new jquery would be:
var test = $("#Clicks").load("TOTAL.txt");
var wdt;
$("img").click(function() {
wdt = setTimeout(serversync, 3000);
test = parseInt(test) + 1;
});
function serversync(){
$.post('ManageClick.php?count='+test);
}
In this code I added the serversync function. It runs after 3000 ms have gone for the setTimeout(). This timeout gets fired when the user clicks, but if there's a click again, the timer resets.
Finally, you should pass the new count value to the ManageClick.php script. I passed it as the count GET attribute (which you can retrieve in your php by $_GET['count']
Of course, this is not perfect nor safe (I could easily fake a massive count to be sent to the server, but that's another story), but it's the idea
Your webserver is detecting a long running script based on some configuration. I'd bet if you take out the sleep function, it would no longer detect a loop.
Also, if you are expecting the value in TOTAL.txt to increase, be sure to cast as integer.
$a = fread($storage,filesize("TOTAL.txt"));
$a = (integer) $a; // cast as integer
$a++; // now you can increase it
To further mitigate this issue, if you must keep the lseep() function, use the following steps in your html/js:
click_button (call ajax)
disable_button (while ajax is running/php is sleeping)
accept_ajax_return_value (when ajax responds)
re-enable button (after ajax is complete and can go again)

Linking into a page with a hash fragment (so user lands at specific content on page) issues

The Feature I Want:
I want to give a user a link like mysite.com/foo#bar so when they hit this link they land on the page foo and are scrolled half way down the page to the content with the id bar. It should be noted that this link will always be clicked from off site or typed into the address bar manually, the user will not already be on the page with all assets loaded.
Also fyi I am using angular and the page in question each bit of content is in an element directive, and in each directive template there are images
The Issue:
Easy enough right? Well I'm running into some problems, most of the time it works, but maybe 40% of the time it doesn't and the user lands above the content, I believe this is because the browser scrolls to the correct point on the page, but then slightly afterward images are loaded in above it pushing the rest of the page down, leaving the user in a random unintuitive spot. (For some reason the failure rate seems to be worse on iPhones...)
What I've Tried So Far:
In a run function I look for a hash fragment on any route and scroll to it if it exists.
if($location.hash()) {
$anchorScroll();
}
I've tried:
Wrapping it in a timeout
This works sometimes but is obviously not consistent, sure I can set it to 500ms and on a great wifi connection it's fine, but not on a mobile with poor signal
listening for $viewContentLoaded
Too fast, ui-router seems to fire this event way before the page is rendered
Emitting an event in each post-link function for all directives on the page.
link: function ($scope) {
$scope.$emit('loadingFinished');
Then picking that up again in the run function
$scope.$on('loadingFinished', function () {
$timeout(doAnchorScroll, 500);
}
This raised the success rate but still wasn't foolproof. And I witnessed it leaving the user stranded in weird spots mainly on iPhones.
Can anyone suggest a way of detecting a moment where it is safe to scroll, or perhaps some other way of ensuring landing in the correct spot?
Two things - first is a user-scroll should prevent it - you don't want to be scrolling the view if they've already scrolled. Second is listening for the images to finish loading.
Listening for the images is quite easy:
$("img").one("load", $anchorScroll);
Then in $anchorScroll I'd suggest checking if all images have loaded, and returning immediately if not (bonus points if you only check images above the anchor - but only doing a quick reply):
var scrolled = false;
function $anchorScroll() {
var allLoaded = true;
$("img").each(function() {
if (!this.loaded) {
return allLoaded = false;
}
});
if (scrolled || !allLoaded) {
return;
}
...
The scrolling is possibly slightly harder - you can check for scroll events, but they are slightly different between platforms - and might even get fired for the manual scroll - if you find that happens then simply have a global that says "I'm scrolling here" and ignore it, otherwise:
$(document).one("scroll", function() { // Use ".on" if this gets fired for code...
scrolled = true;
});
Note that you probably don't need to care about failed image loads, or ones that have already loaded, since your initial call to $anchorScroll() will catch them.

javascript window confirm pops up several times

i am trying to use the confirm method but for some reason the confirm window pops up several times. I googled and tried different things but unfortunately I can't get it running properly. The code is the following:
//user clicks on the delete button
$("#deletePopUpImage").click(function(){
console.log("deletePopUpimageCalled");
//get the id of the image
id = ($(this).parent().prop("id"));
//create the ajax request
data = "typ=function&functionType=deleteUserImage&id="+id;
//open the confirm box
var r = confirm("Are you sure that you want to delete this image?");
if (r == true) {
console.log("loadAjaxCAlled");
//Ajax call
loadAjax(data);
//hide the image and the loader
hideImagePopup();
} else {
//do nothing
}
});
The strange thing is that sometimes the confirm window pops up twice, sometimes three times and sometimes as expected once. That's why inserted the two console.logs.
"deletePopUpimageCalled" always appears just once. However "loadAjaxCAlled" appears several times.
In the success callback of the Ajax request I am just hiding the thumbnail div.
Do you know what's wrong with my code above?
Thanks
Stefan
Probably the code that attaches the event:
$("#deletePopUpImage").click(function(){...});
is invoked several times. Every invocation of .click(...) makes a new handler that fires when the button is clicked.
Some browsers stack up log the same entries into one (so the log doesn't extend so fast), that could be the reason you don't see "deletePopUpimageCalled" many times.
It would the best to check this by debugging it in the browser.
Ok I found the problem. In the Ajax success handler I set the div of the image, that was deleted, to display:none instead of deleting it. Thus divIds could occur twice, three times, etc. After changing the code to delete, it worked smoothly.

Javascript - Loop keeps running after page refresh

Today one of the weirdest things i have ever seens just happened.
I have a loop in a page that does a synchronous ajax request for each element of the loop. Since it was taking too long i decided to stop the loop by refreshing the page.
When the page loaded i couldn't click on any element of the page so i checked Firebug console and i saw that the ajax calls of the previous loop were still being done (the loop is set to start after i click on a link, so it can't start as soon as page loads).
To stop the loop i had to close the current tab and open my page in a new one.
It's worth mentioning that i have a datatables table on that page and i have enabled the option to save the table state, maybe this is interfering with my code (the loop itself is not part of the datatables initialization, though it uses data from the table).
I have also noticed that some things of the loop aren't being done. It should've changed the page of the datatable by time to time, and it should've written in the javascript console, both things don't happen after i refresh the page, the ajax calls are still going though.
Here's the code where the loop is contained:
//This variable will contain a reference to the datatable
var oTable;
var isWorking=false;
//Change the datatables page
function changeTablePage(oTable, page, clear){
if(clear){
oTable.fnClearTable();
oTable.fnDraw();
}
oTable.fnPageChange(page);
}
//This part is inside a document.ready block
$(document).on("click", ".validation-all-click", function(event){
if(!isWorking){
isWorking=true;
//saves the current page, will be needed for later
var page=oTable.fnPagingInfo().iPage;
var numberPage=0;
var done=false;
while(!done){
console.log("page: "+numberPage);
changeTablePage(oTable, numberPage, false);
var nNodes = oTable.fnGetNodes();
var len=nNodes.length;
$('.validation-click', nNodes).each(function( index, value ){
//id of the element to be validated
var id=$(value).data("rowid");
//Calls the validation url
$.ajax({
url: "/validate?id="+id,
async: false
});
});
//if the datatables page has 0 items, then it's done
if(len==0){
done=true;
}
numberPage++;
}
//goes back to the original page
changeTablePage(oTable, page, true);
isWorking=false;
}
});
I don't want this behavior to happen, but i have no idea on why it's happening and how to prevent it
Thanks for sharing your story. I don't see any specific question in the post, so I'll just comment on whatever I feel like.
As I understand it, browsers aren't required to redraw the UI while JavaScript is running. Since there's a script blocking on a synchronous ajax request, maybe it's to be expected that you don't see the changes to the table until the loop finishes.
Furthermore, it may also be that the browser isn't required to destroy a page while its scripts are running. That would explain why you saw requests in Firebug after refreshing the page--perhaps the previous copy of the page was still running in a hidden state.
edit: valepu reports in a comment, below, that the table does change while the script is running. That's fine. The browser can probably determine that it can redraw the UI during the ajax call (which doesn't affect the JavaScript environment). valepu also clarifies that the visual updates stop after refreshing the page, though the requests continue to go out. This is also consistent with the idea that the browser has just hidden the previous page (until it finishes) and loaded up a new copy of the page when refreshing.
As for how to prevent it: the most reliable way would be to use asynchronous requests, or otherwise yield between requests. Sorry, folks.
I have solved by adding a variable that will stop the loop when i exit the page:
var stopLoop=false
$( window ).unload(function() {
stopLoop=true;
});
both loops will now check if this variable is false before executing the code inside the loop.
This works on Firefox but not on Chrome though.
-- EDIT --
In the end i have solved by editing the code in order to make the ajax calls asynchronous and using the callback functions to continue the cycle, though it was no simple task (some days later i found a new solution that allowed me to do all that i needed in a single call when i found out how to recover the parameters used by datatables to retrieve data, but this has nothing to do with the original question). So, for future references: expect this "weird" behaviour when making a loop with ajax synchronous calls

Categories

Resources