Related
I have a javascript function that has about 4 ajax requests in it. It typically takes less than a second to run. However, I'm working on the error handling now and was wondering. How long, in seconds, should I allow my javascript function to try to keep working until I manually cancel it and allow the user to try again?
Here's what the function in question looks like. (not everything is there, but it could potentially have (1000*5000*3)+(70)+(1000)+(6)+(2500) bytes being sent)
function saveChanges(bypassDeckSave){
// bypassDeckSave = undefined - does not bypass
showSavedNotification_check = 1;
if(userid != 0){
//values in database
var subjectID = $('.lib_folder_id').val(),
folderID = $('.lib_subject_id').val();
if(subjectID == 0 || folderID == 0){//if database values null, ask for some
console.log("db deck location not saved, asked for it");
//values to set to
var setFolderID = $('.libDeckLocationModifierDiv .folders li.on').val(),
setSubjectID = $('.libDeckLocationModifierDiv .subjects li.on').val();
if(isNaN(setFolderID) || isNaN(setSubjectID) ||
setFolderID == 0 || setSubjectID == 0)
{
openDeckLocationDiv();
showSavedNotification_check = 0;
return;
}
}
}
var deck_id = $('.deck_id').val();
if(deck_id == 0){
// create a new deck
createDeckThenSave();
return;
}
if(userid != 0){
//values in database
var subjectID = $('.lib_folder_id').val(),
folderID = $('.lib_subject_id').val();
if(subjectID == 0 || folderID == 0){//if database values null, ask for some
//values to set to
saveDeckLocation();
}
}
// removes empty rows
$('.editMain li').each(function(){
var one = $(this).find('.text1').val(),
two = $(this).find('.text2').val();
if(one == "" && two == ""){
//remove this row and remove value from updateSaveArray + add to delete array
var currentval = $(this).val();
var rowid = ".row_"+currentval;
updateSaveArray = jQuery.grep(updateSaveArray, function(value) {
return value != currentval;
});
$(rowid).remove();
updateDeleteArray[updateDeleteArray.length] = currentval;
}
});
if(bypassDeckSave == undefined){
// save deck info to db
var deckname = $('.editDeckNameInput').val(),
cardCount = $('.editMain li.mainLi:visible').length,
deckTermLanguage = $('.selector.one select').val(),
deckDefinitionLanguage = $('.selector.two select').val(),
deckThirdBoxLanguage = $('.selector.three select').val(),
deckDescription = $('.editMoreDeckOptionsDiv textarea').val();
if($('.editMoreDeckOptionsSelector .onlyme').hasClass("on")){
var viewPreferences = 1;
}else{
var viewPreferences = 0;
}
if($('.editUseThirdboxDiv').hasClass('on')){ var thirdbox = 1;
}else{ var thirdbox = 2; }
// console.log("deckInfoSave called");
$.ajax({
type: "POST",
url: "/edit/deckInfoSave.php",
data: { pDeckid: deck_id, pDeckname: deckname, pCardCount: cardCount,
pDeckTermLanguage: deckTermLanguage, pDeckDefinitionLanguage: deckDefinitionLanguage,
pDeckThirdBoxLanguage: deckThirdBoxLanguage, pThirdbox: thirdbox,
pDeckDescription: deckDescription, pViewPreferences: viewPreferences
}
})
.done(function(data){
// console.log(data);
// decksaved = 1;
saveDeckInfoHasFinished = 1;
});
}else{
saveDeckInfoHasFinished = 1;
}
// prepares edited card array
// gets all needed values and stores in holdSaveCardArray
var holdSaveCardArray = [];
for (i = 0; i < updateSaveArray.length; ++i) {
var currentCard_id = updateSaveArray[i],
rowidClass = ".row_"+currentCard_id,
text1val = $(rowidClass+" .text1").val(),
text2val = $(rowidClass+" .text2").val(),
text3val = $(rowidClass+" .text3").val();
cardOrder = $(".editMain li.mainLi:visible").index($(rowidClass)) + 1;
holdSaveCardArray[holdSaveCardArray.length] = {
"card_id": currentCard_id,
"text1val": text1val,
"text2val": text2val,
"text3val": text3val,
"cardOrder": cardOrder
};
}
// console.log(print_r(holdSaveCardArray));
// delete cards start
// deletes any card with an id in updateDeleteArray
$.ajax({
type: "POST",
url: "/edit/deleteCards.php",
data: { pDeck_id: deck_id, pDeleteArray: updateDeleteArray }
})
.done(function( msg ) {
// $('.temp').append(msg);
updateDeleteArray = [];
deleteCardsHasFinished = 1;
});
// save cards to database
// loops through each card that had changes made to it
$.ajax({
type: "POST",
url: "/edit/saveCardsArray.php",
dataType: "JSON",
data: { pDeck_id: deck_id, pCardArray: holdSaveCardArray}
}).done(function(data){
for (var i = 0; i < data.length; i++) {
var temp_id = data[i]["temp_id"], // new id
card_key = data[i]["card_key"], // old id
currentClassName = 'row_'+temp_id,
currentClass = '.row_'+temp_id,
nextClassName = 'row_'+card_key;
$(currentClass).val(card_key);
$(currentClass).removeClass(currentClassName).addClass(nextClassName);
}
saveCardsHasFinished = 1;
});
updateSaveArray = [];
// update order start // uses li value
updateOrderArray = [];
$('.editMain').find(".mainLi").each(function(){
var temp = $(this).val();
updateOrderArray[updateOrderArray.length] = temp;
});
$.ajax({
type: "POST",
url: "/edit/orderCards.php",
data: { pUpdateOrderArray: updateOrderArray }
})
.done(function( msg ) {
updateOrder = 0;
updateOrdersHasFinished = 1;
});
closeLibDLM(); console.log("closeLibDLM1");
changeSaveStudyButton(1);
} //saveChanges function end
So you could totally set an arbitrary timeout, or even a timeout that should encompass everything finishing on time? But, what happens when it doesn't? What happens when it takes longer to finish?
At that point, you're going to be in quite a pickle. I did not thoroughly read your code, but I would highly advise trying to use a callback() or Promise to end your function. And, not set a timeout. - This is a cleaner solution in that things happen when you want them, and after some defined has happened. Time is a relative, and finicky attribute of our world (Einstein proved this =P) that would be best be used as your friend, and not your enemy.
The counter argument would be, well sometimes things just hang. And, that is totally valid. For that case, you could set a timeout for a long period of time. But, again, that is still a 'hacky' way to handle things. In this case, I would try to create some handling to detect errors, or timeouts. i.e you could periodically check the page for a status. You could check to see which events are in existence that you could hook into.
If you could share in what instances our program hangs, I could better suggest a solution. Otherwise this question may end up being opinionated based on coding styles.
Hope this helps in some regard :)
I've worked in the Aerospace Aviation Industry and have asked a similar question when working with Microcontrollers. It seems you are looking for an appropriate timeout value based on calculation, but this may not be necessary in your case. Often times timeout values are more or less arbitrary. If your function executes in an average of roughly 1 second, maybe your timeout value should be set to 3 seconds. You should come to a conclusion based on testing.
So the JSON object I'm trying to reach sometimes does not exist.
Notice: Undefined index: movies in C:\xampp\htdocs\example\game.php
I'm reaching for it in the Steam API with this code on game.php:
$GLOBALS['gameTrailer'] = $game_json[$trimmed]['data']['movies'][0]['webm']['max'];
echo json_encode(array(
'gameTrailer' => $GLOBALS['gameTrailer'],
//+ other variables
));
I'm using AJAX to poke game.php like so on index.php:
function returnGame () {
$.ajax({
url: "game.php",
type: "post",
dataType: 'json',
success: function(data){
console.log(data);
$('#video').removeAttr('src');
///// Game name /////
$('#gameName').html(data.gameName);
/////////////////////
////// Append and load video /////
var videoSrc = data.gameTrailer;
var video_block = $('#video');
if (videoSrc !== null && videoSrc !== undefined) {
video_block.load();
document.querySelector('video').src = videoSrc;
} else {
$("#gameTrailer").find("#gameScreenshot").attr("src", data.gameScreenshot);
}
//////////////////////////////////
},
});
}
When movies is null, the AJAX function does nothing. The video does not change to blank, and the movie title is not updated to something new. When movies is not undefined, it works perfectly.
I can't seem to catch $GLOBALS['gameTrailer'] as undefined and re-iterate or replace with screenshot instead of movie though, not on game.php or index.php. I've tried things like if(empty()) {} and if($GLOBALS['gameTrailer'] == NULL) {}, but even though the error code on game.php tells me that it is undefined, it seems to act like it's not.
Any ideas will be much appreciated. Thanks.
EDIT: Full game.php code:
<?php
if(isset($_POST)) {
fetchGame();
}
function fetchGame() {
////////// ID-picker //////////
$f_contents = file("steam.txt");
$url = $f_contents[mt_rand(0, count($f_contents) - 1)];
$answer = explode('/',$url);
$gameID = $answer[4];
$trimmed = trim($gameID);
////////// Fetch game //////////
$json = file_get_contents('http://store.steampowered.com/api/appdetails?appids='.$trimmed);
$game_json = json_decode($json, true);
////////// Store variables //////////
$GLOBALS['gameName'] = $game_json[$trimmed]['data']['name'];
$GLOBALS['gameTrailer'] = $game_json[$trimmed]['data']['movies'][0]['webm']['max'];
$GLOBALS['gameScreenshot'] = $game_json[$trimmed]['data']['screenshots'][0]['path_full'];
$GLOBALS['gameImage'] = $game_json[$trimmed]['data']['header_image'];
$GLOBALS['gameId'] = $trimmed;
$GLOBALS['free'] = $game_json[$trimmed]['data']['is_free'];
$GLOBALS['price'] = $game_json[$trimmed]['data']['price_overview']['final'];
if(!isset($GLOBALS['price']) && ($GLOBALS['gameTrailer'])) {
fetchGame();
}
if ($GLOBALS['free'] === TRUE) {
$GLOBALS['final_price'] = "Free";
} elseif($GLOBALS['free'] === FALSE || $GLOBALS['final_price'] != NULL) {
$GLOBALS['final_price'] = $GLOBALS['price'];
} else {
$GLOBALS['final_price'] = "-";
}
}
////////// Return to AJAX (index.php) //////////
echo
json_encode(array(
'gameName' => $GLOBALS['gameName'],
'gameTrailer' => $GLOBALS['gameTrailer'],
'gameImage' => $GLOBALS['gameImage'],
'gameId' => $GLOBALS['gameId'],
'finalPrice' => $GLOBALS['final_price'],
'gameScreenshot' => $GLOBALS['gameScreenshot']
))
;
?>
It breaks on line 23 ($GLOBALS['gameTrailer'] = $game_json[$trimmed]['data']['movies'][0]['webm']['max']; as an undefined index)
Okay, so here is an example update to the code provided going by the comments made on the question.
Notes:
1) Don't use $GLOBALS unless you know what you're doing and why you're using it. In this case, it doesn't appear required. Updated to $game as it's holding game details.
2) You need to check whether something exists before you try and access it. So, the isset you previously had is useless as you've already accessed a non-existing array item. Removed that check.
3) Recursion is good, but again, you need to know what you're doing, and why you're using it. I suspect this was unintentional anyway but was removed as part of 2.
4) You state that having a video (and price by the looks of it) is a requirement for this function, so you should check that up front. Note that the first thing after getting the ID, is to see if there's a video. Why do work just to find we can't use it?
5) You want to try a different game if there is no video, so we wrap the check and assignments in a loop, and continue if the video isn't there. Note that you might want to restrict this to n number of tries otherwise you might end up waiting ages for your script to find a game that has a video, but that's for you to decide.
<?php
if(isset($_POST)) {
fetchGame();
}
function fetchGame() {
$gameFound = false;
while(!$gameFound) {
////////// ID-picker //////////
$f_contents = file("steam.txt");
$url = $f_contents[mt_rand(0, count($f_contents) - 1)];
$answer = explode('/',$url);
$gameID = $answer[4];
$trimmed = trim($gameID);
////////// Fetch game //////////
$json = file_get_contents('http://store.steampowered.com/api/appdetails?appids='.$trimmed);
$game_json = json_decode($json, true);
if(!isset($game_json[$trimmed]['data']['movies'][0]['webm']['max']) || !isset($game_json[$trimmed]['data']['price_overview']['final'])) {
continue;
}
$gameFound = true;
////////// Store variables //////////
$game['gameName'] = $game_json[$trimmed]['data']['name'];
$game['gameTrailer'] = $game_json[$trimmed]['data']['movies'][0]['webm']['max'];
$game['gameScreenshot'] = $game_json[$trimmed]['data']['screenshots'][0]['path_full'];
$game['gameImage'] = $game_json[$trimmed]['data']['header_image'];
$game['gameId'] = $trimmed;
$game['free'] = $game_json[$trimmed]['data']['is_free'];
$game['price'] = $game_json[$trimmed]['data']['price_overview']['final'];
if ($game['free'] === TRUE) {
$game['final_price'] = "Free";
} elseif($game['free'] === FALSE || $game['final_price'] != NULL) {
$game['final_price'] = $game['price'];
} else {
$game['final_price'] = "-";
}
}
}
////////// Return to AJAX (index.php) //////////
echo
json_encode(array(
'gameName' => $game['gameName'],
'gameTrailer' => $game['gameTrailer'],
'gameImage' => $game['gameImage'],
'gameId' => $game['gameId'],
'finalPrice' => $game['final_price'],
'gameScreenshot' => $game['gameScreenshot']
));
?>
Note this code is untested, but I hope gives you an idea of how to proceed.
I am trying to get data to display in a table. I don't know what I am doing wrong, but when I get the data from my page it is an array of single characters. I could parse this myself but would prefer to know what I am doing wrong.
I have this php to get the data:
function BuildViewerCombo($autocomplete) {
$wholeNumberCombo = array();
$dbhandle = DB_Connect();
$result = QueryForward($dbhandle, SQL_WholeNumbersPartial($autocomplete));
while($wholeNumber = sqlsrv_fetch_array($result))
{
$wholeNumberCombo[] = array($wholeNumber['DocumentNbr'] => 'Number', $wholeNumber['DocumentRevision'] => 'Revision');
}
//close the connection
sqlsrv_close($dbhandle);
return $wholeNumberCombo;
}
Which is called from this page
<?PHP
include "Scripts/DB_Functions.php5" ;
include "Scripts/SQL_Viewer.php5" ;
$wholeNumber = $_GET['wholeNumber'];
echo json_encode(BuildViewerCombo($wholeNumber));
?>
Which gets loaded from this function
function toggleDropdown()
{
var wholeNumberData
var wholeNumber = document.getElementById('WholeNumber').value;
if (wholeNumber != '') {
wholeNumberData = GetData('wholeNumber', wholeNumber);
var table = document.getElementById("wholeNumberDropdown");
alert ('WN = ' + wholeNumberData.length);
alert (wholeNumberData);
for (var i in wholeNumberData) {
alert(wholeNumberData[i]);
}
}
else {
alert("Please enter a whole number.");
}
}
By calling this function:
function GetData(getType, param) {
var http = new XMLHttpRequest();
http.open("GET", 'ViewerWholeNumbers.php?wholeNumber=' + param, false);
http.setRequestHeader("Content-type","application/json");
http.onload = function() {
}
http.send('wholeNumber=' + param);
return http.responseText;
}
The data that gets returned is:
[{"SS3999":"Number","A":"Revision"},{"SS3999":"Number","11":"Revision"},
{"SS3999":"Number","11":"Revision"},{"SS3999":"Number","11":"Revision"},
{"SS3999":"Number","":"Revision"},{"SS3999":"Number","11":"Revision"},
{"SS3999":"Number","":"Revision"},{"SS3999":"Number","11":"Revision"},
{"SS3999":"Number","11":"Revision"},{"SS3999":"Number","A":"Revision"},
{"SS3999":"Number","11":"Revision"},{"SS3999":"Number","A":"Revision"},
{"SS3999":"Number","11":"Revision"},{"SS3999":"Number","A":"Revision"},
{"SS3999":"Number","":"Revision"}]
But alert ('WN = ' + wholeNumberData.length); returns 546 and when I try to loop through the array I get a single character for each element instead of the values.
First off, your associative array is flipped. You need to change
array($wholeNumber['DocumentNbr'] => 'Number', $wholeNumber['DocumentRevision'] => 'Revision');
to
array('Number' => $wholeNumber['DocumentNbr'], 'Revision' => $wholeNumber['DocumentRevision']);
You need that in order to access the elements of the JSON. Then, in your loop, you would use wholeNumberData[i].Number to get the number and wholeNumberData[i].Revision to get the revision.
Update:
As #jeroen pointed out, you need JSON.parse() to convert the return string to JSON. In your GetData function replace your return with this:
return JSON.parse(http.responseText);
Hi I'm making a javascript script which now is getting really hard to edit, and hard to understand for other people, I'll put it here hoping someone can understand it and give some advice or help
function fetchMember(id, select, sitename, total) {
return function() {
progress();
$.ajax({
type: 'POST',
url: "script.php",
data: $("#fetch").serialize() + "&id=" + id,
success: function(data) {
isUser = ($(data).text().indexOf("Invalid User") == -1);
if (isUser) {
username = $(data).find(".normal").text();
saved = id - invalid;
$.ajax({
type: 'POST',
url: "save.php",
data: {'username': username},
success: function(data) {
$("#test").append(id+" "+data + "<br />");
select.text(sitename+"("+saved+"/"+total+")"); //Updating numbers of fetched profiles on the frontend
}
});
}
else
invalid++; //loop again here because a user wan't valid
progress();
}
});
}
}
for (i = 0; i < members; i++) {
fetched++;
setTimeout(fetchMember(fetched, select, sitename, total), wait*i);
}
basically what I need to do is to loop again if at the end of the operation there are some invalid users, any help is really appreciated
I wonder if this code would help you, though it's not completely adapted for your case and wasn't tested. The main principle is the recursive call of memberFetch function. No need for timeouts in this case - it won't make any new requests to the server until it got a response for the last one. Feel free to ask any questions, but please try to experiment yourself :)
var currentId = 0; // Current member id
var membersNum = 10; // There are 10 members from 0 to 9
var neededValidUsersNum = 5; // We need only 5 valid users...
var valudUsersNum = 0; // ... but now we have 0 of them
// Let's make an array of all possible id's
// It will be a queue - we will try to fetch the first id
// In case of success - save data, remove that id from the queue, fetch the nex one
// Otherwise - put it at the back of the queue to try it again later
var possibleIds = [];
for (var i = 0; i < membersNum; i++) {
possibleIds.push(i);
}
// Fetched user data storage
var userData = {};
function fetchMember(id) {
var data = "some data";
$.post('script.php', data)
.done(function(responseData){
onFetchMemberDone(id, responseData);
})
.fail(function(){
onFetchMemberFail(id);
});
}
function onFetchMemberDone(id, responseData){
// Save recieved user data
userData[id] = responseData;
// Bump valid users num
valudUsersNum++;
// If there are not enough valid users - lets continue:
if (valudUsersNum < neededValidUsersNum) {
// Remove valide user from the queue (it was the first one)
possibleIds.shift();
// try to fetch the next one
var nextPossibleId = possibleIds[0];
fetchMember(nextPossibleId);
}
}
function onFetchMemberFail(id){
// add failed user to the end of the queue
possibleIds.push(id);
// try to fetch the next one
var nextPossibleId = possibleIds[0];
fetchMember(nextPossibleId);
}
// Lets launch the cycle! It doesn't look like one because it works through recursive calls
onFetchMember(0);
can anyone help me...my script function automatically updates what's inside the output of my textboxes from the database if I change the values in the table in the database without refreshing the page or clicking the button again to execute the script.
After a seconds later my page is lagy. I can't move my mouse freely. Is there any way how to automatically update data in my textboxes using javascript if I change the values in my table in my database?
current script:
$(document).ready(function(){
var timer ;
$('#send_search_form').click(function(event){
event.preventDefault();
$(".search_form_input").val('');
$(".empty_batchcode").html("Doesn't exist!");
clearInterval(timer);
updateTextboxes();
});
function updateTextboxes(){
$.ajax({
url:"search.php",
type:"GET",
data: { term : $('#query').val() },
dataType:"JSON",
success: function(result) {
var ii = 1;
for (var i = 0; i < result.length; i++) {
$('#funiq_id').html(result[i].value).show();
$('#t_region').val(result[i].region).show();
$('#t_town').val(result[i].town).show();
$('#t_uniq_id').val(result[i].uniq_id).show();
$('#t_position').val(result[i].position).show();
$('#t_salary_grade').val(result[i].salary_grade).show();
$('#t_salary').val(result[i].salary).show();
$('#id'+ii+'').val(result[i].atid).show();
$('#aic'+ii+'').val(result[i].atic).show();
$('#name'+ii+'').val(result[i].atname).show();
$('#other_qual'+ii+'').val(result[i].other_sum).show();
$('#interview'+ii+'').val(result[i].interview_sum).show();
ii++;
}
if(timer == 1){ // if timer has been cleared
timer = setInterval(updateTextboxes,1000); // <-- change 1000 to the value you want
}
}
});
timer = setInterval(updateTextboxes,1000);
}
});
search.php code:
<?php
if (isset($_GET['term'])) {
$q = $_GET['term'];
mysql_connect("localhost", "root", "");
mysql_select_db("klayton");
$query = mysql_query
("
SELECT DISTINCT
ROUND((SELECT SUM(t2.inttotal)
FROM app_interview2 AS t2
WHERE t2.atic = t.atic)/7,1)
AS interview_sum,
ROUND((SELECT SUM(o2.ototal)
FROM other_app2 AS o2
WHERE o2.oaic = t.atic)/7,1)
AS other_sum,
atid,
atic,
atname,
region,
town,
uniq_id,
position,
salary_grade,
salary
FROM app_interview2 AS t
WHERE uniq_id = '$q'
GROUP BY t.atname HAVING COUNT(DISTINCT t.atic) ");
$data = array();
while ($row = mysql_fetch_array($query)) {
$data[] = array(
'value' => $row['uniq_id'],
'atid' => $row['atid'],
'atic' => $row['atic'],
'region' => $row['region'],
'town' => $row['town'],
'uniq_id' => $row['uniq_id'],
'position' => $row['position'],
'salary_grade' => $row['salary_grade'],
'salary' => $row['salary'],
'atname' => $row['atname'],
'other_sum' => $row['other_sum'],
'interview_sum' => $row['interview_sum']
);
}
header('Content-type: application/json');
echo json_encode($data);
}
?>
You are setting more and more setIntervals inside setIntervals and never clearing them. Remember, each setInterval call results in function running multiple times, once every N milliseconds. As the time passes, the amount of running code increases exponentially, which causes lag.
Consider using setTimeout instead. Also, setTimeout or setInterval? might be a good read.
The documentation on the above methods:
https://developer.mozilla.org/en/docs/Web/API/window.setTimeout
https://developer.mozilla.org/en/docs/Web/API/window.setInterval
Two things I have noticed. The first is the setInterval(). Every loop-illiteration it starts another timer. 1sec = 1 interval, 2sec=2, 3sec=4(!), 4sec=8(!!). So after a few seconds, your browser's going crazy. Use setTimeout() instead :)
Number two is saving the DOMreference. Every illiteration you select the id's and set a new value. Every second jQuery finds the elements. It's better to save them first, and then use the saved reference. I've done both:
var $funiq_id = $('#funiq_id'),
$t_region = $('#t_region'),
$t_town = $('#t_town'),
$t_uniq_id = $('#t_uniq_id'),
$t_position = $('#t_position'),
$t_salary_grade = $('#t_salary_grade'),
$t_salary = $('#t_salary');
function updateTextboxes(){
$.ajax({
url:"search.php",
type:"GET",
data: { term : $('#query').val() },
dataType:"JSON",
success: function(result) {
if(result.changedOccured){ // make php send if there are changes (true/false)
var ii = 1;
var resultLength = result.length;// Out of the loop will improve a tiny bit
for (var i = 0; i < resultLength; i++) {
$funiq_id.html(result[i].value).show(); // reference
$t_region.val(result[i].region).show(); // reference
$t_town.val(result[i].town).show(); // reference
$t_uniq_id.val(result[i].uniq_id).show(); // reference
$t_position.val(result[i].position).show(); // reference
$t_salary_grade.val(result[i].salary_grade).show(); // reference
$t_salary.val(result[i].salary).show(); // reference
$('#id'+ii+'').val(result[i].atid).show();
$('#aic'+ii+'').val(result[i].atic).show();
$('#name'+ii+'').val(result[i].atname).show();
$('#other_qual'+ii+'').val(result[i].other_sum).show();
$('#interview'+ii+'').val(result[i].interview_sum).show();
ii++;
}
}
}
}
if(timer == 1){ // if timer has been cleared
timer = setTimeOut(updateTextboxes,1000); // <-- change 1000 to the value you want
}
}
Small note: Saving the DOM references into variables need to happen at the bottom of the page, or on a $(document).ready(). The elements have to exists before you can select them
For better performance, make php send wether or not something has changed. If something has, do the code you have now. If no changes, DONT UPDATE THE ELEMENTS. It's a waste of power to change something from 'abc' to 'abc'.