I'm creating online chat, but I'm wondering while using jQuery .load() in my script, my browser seems to get slow. When i checked the inspect element "Net" section, it loads bunches of GET-data... etc.
I would like to know if there's a better script solution with this code to prevent chat being heavy in the background while the data keeps looping in the background to check who's keep coming online/offline.
setInterval('loadThis()', 5000);
function loadThis () {
$("#loads").load('includes/users.php', function(){
$(".chat-side-panel li").each(function(i){
i = i+1;
$(this).addClass("stats"+i);
var status = $(".stats"+i).find("span.bullet").data("status"),
flag = $(".stats"+i).find("span.mail").data("flag");
if(status == 1) {
$(".stats"+i).find("span.bullet").addClass("online");
}
if(flag == 1) {
$(".stats"+i).find("span.mail").addClass("active");
}
});
});
}
the Chat-Side-Panel will be the main panel, and LI will be the listings of users including their status (online/offline) and flag (message received). As for the standard, what can you suggest for the setInterval time loading (if 5sec. is enough) or should i increase it.
Thanks for your input for this.
PS. We're doing this with both PHP/MySQL also.
One issue I see is that you keep re-querying the DOM for the same elements. Get them once, re-use them thereafter:
var load_target = $('#loads');
function loadThis () {
load_target.load('includes/users.php', function () {
load_target.find('.chat-side-panel li').each(function (i) {
var stats_li = $(this),
bullet = stats_li.find('span.bullet'),
mail = stats_li.find('span.mail');
bullet.toggleClass('online', (bullet.data('status') == 1))
mail.toggleClass('active', (mail.data('flag') == 1));
});
});
}
I don't know all of your involved logic or what the rest of your system looks like, so this particular code may not work exactly. It should simply serve as a re-factor done in a vacuum to show what that function could look like if you stopped hitting the DOM so hard.
Also, use of setInterval is not generally recommended. If the load of the remote file takes a while, you could end up calling loadThis() again before a previous one was completed. This would compound your DOM issues if calls to loadThis() began stacking up. Recursive use of setTimeout is preferred in a situation like this. Here is the above code modified to run recursively, and some usage examples below that:
var load_target = $('#loads'),
loadThis = function (start_cycle) {
$.ajax({
url: 'includes/users.php',
dataType: 'html',
type: 'GET',
success: function (response) {
load_target
.html(response)
.find('.chat-side-panel li').each(function (i) {
var stats_li = $(this),
bullet = stats_li.find('span.bullet'),
mail = stats_li.find('span.mail');
bullet.toggleClass('online', (bullet.data('status') == 1))
mail.toggleClass('active', (mail.data('flag') == 1));
});
},
complete: function () {
if (typeof start_cycle !== 'boolean' || start_cycle) {
load_target.data('cycle_timer', setTimeout(loadThis, 5000));
}
}
});
};
//to run once without cycling, call:
loadThis(false);
//to run and start cycling every 5 seconds
loadThis(true);
// OR, since start_cycle is assumed true
loadThis();
//to stop cycling, you would clear the stored timer
clearTimeout(load_target.data('cycle_timer'));
Last years (around 2012) I developed a chat system for a social network, and saw that
Using setInterval issue is when the request is being sent regularly, without waiting or carry about the result of the first requests in the queue. Sometimes the script can not respond and Mozilla or IE asks the user whether he should block or wait for the non-responding script.
I finally decided to use setTimeout instead. Here is what I did (I use $.getJSON so please study the example and how can use load instead)
function loadThis () {
$.getJSON('url').done(function(results){
//--use the results here
//then send another request
setTimeOut(function(){
loadThis();
},5000);
}).fail(function(err){
//console.log(print(err))
setTimeOut(function(){
loadThis();
},1000);
});
}
loadThis();
PS.: I would like to mention that the time depends on our many items are to be retrieved in your users.php file. Maybe you should use the paging tip. Your users.php can then treat url params users.php?page=1&count=100 for the first request, users.php?page=2&count=100 for the second until the results rows number is 0.
EDITS: In addition, I suggest you consider not interacting with the DOM every time. It is important too.
Related
I'm trying to develop an application in which it is very important to detect changes in a database in real time. I have devised a method to detect the changes now by running an ajax function and refreshing the page every 3 seconds, but this is not very efficient at all, and on high stress levels it dosen't seem like an effective solution.
Is there any way I can detect if some change has been made in the database instantly without having to refresh the page? The sample code is attached. I'm using php as my server side language, with html/css as the front end.
$(document).ready(function() {
$('#div-unassigned-request-list').load("atc_unassigned_request_list.php");
$('#div-driver-list').load("atc_driver_list.php");
$('#div-assigned-request-list').load("atc_assigned_request_list.php");
$('#div-live-trip-list').load("atc_live_trip_list.php");
setInterval(function() {
$.ajax({url:"../methods/method_get_current_time.php",success:function(result){
$("#time").html(result);
}});
}, 1000)
setInterval( function() {
$.ajax({url:"atc_unassigned_request_list.php",success:function(result){
$("#div-unassigned-request-list").html(result);
}});
$.ajax({url:"atc_driver_list.php",success:function(result){
$("#div-driver-list").html(result);
}});
$.ajax({url:"atc_assigned_request_list.php",success:function(result){
$("#div-assigned-request-list").html(result);
}});
} ,2000);
});
Please help!
For me, the best solution is
On the server side write a service that identify the changes
On the client, check this service with websockets preferencially (or ajax if you can not use websockets), then if there have changes, download it, This way you have, economy and velocity with more funcionality
Examples Updated
Using ajax
function downloadUpdates(){
setTimeout(function(){
$.ajax({
url: 'have-changes.php'
success:function(response){
if(response == 'yes'){
// ok, let`s download the changes
...
// after download updates let`s start new updates check (after success ajax method of the update code)
downloadUpdates();
}else{
downloadUpdates();
}
}
});
}, 3000);
}
downloadUpdates();
Using websockets
var exampleSocket = new WebSocket("ws://www.example.com/changesServer");
exampleSocket.onmessage = function(event) {
if(event.data != "no"){
// ok here are the changes
$("body").html(event.data);
}
}
exampleSocket.onopen = function (event) {
// testing it
setInterval(function(){
exampleSocket.send("have changes?");
}, 3000)
}
Here (I have tested it ) and Here some examples of how to use websocokets on php, the problem is you will need to have shell access
i need a a script that will refresh the functions:
$ping, $ms
every 30 seconds, with a timer shown,
i basicly got this script:
window.onload=function(){
var timer = {
interval: null,
seconds: 30,
start: function () {
var self = this,
el = document.getElementById('time-to-update');
el.innerText = this.seconds;
this.interval = setInterval(function () {
self.seconds--;
if (self.seconds == 0)
window.location.reload();
el.innerText = self.seconds;
}, 1000);
},
stop: function () {
window.clearInterval(this.interval)
}
}
timer.start();
}
but it refreshes the whole page, not the functions i want it to refresh, so, any help will be appriciated, thanks!
EDIT:
I forgot to mention that the script has to loop infinatly
This here reloads the whole page:
window.location.reload();
Now what you seem to want to do is reload portions of the page, those portions having been generated by php functions. Unfortunately php is server side so that means you cant get the client browser to run php. Your server runs the php to generate stuff that browsers can understand. In a web browser open a page you made using php and choose to view source and you'll see what I mean.
Here's what you'll need to do:
Make your two functions ping and ms accessable via ajax
Instead of window.location.reload() do a call to jQuery.ajax. on success write to your page
Here's what I think would be the ideal way of dealing with this... I haven't seen the php side of your problem but anyway:
make a file called ping.php and put all your ping function code in there. ditto for ms
in your original php file that called those functions, make a div at each point where you wanted a function call. Give them appropriate ids. Eg: "ping_contents" and "ms_contents"
You can populate these with some initial data if you want.
In your js put in something like this:
jQuery.ajax(
{
url : url_of_ping_function,
data : {anything you need},
type : 'POST', //or 'GET'
dataType: 'html',
success : function(data)
{
document.getElementById("ping_contents").innerHTML = data;
}
});
do another one for the other function
What you want is AJAX, Asynchronous JavaScript and XML
You can use jQuery for that.
I can put an example here, but there is a lot of information to be found on the internet. In the past I wrote my own AJAX code, but since I started using jQuery, it's all a lot easier. Look at the jQuery link I provided. There is some usefull information. This example code might be the easiest to explain.
$.ajax({
url: "test.php"
}).done(function() {
alert("done");
});
A some moment, for example on a click on a button, the file test.php is executed. When it's done, a alert box with the text "done" is shown. That's the basic.
I have been searching all over the internet tonight, saw a lot of "solutions" but not working for me unfortunately. So I will try to get different answer of what I am seeing here on stack and elsewhere and hoping I will find one which will work...
My page has the following javascript bit:
logbook = setInterval(function () {
$.getJSON("php/log.php", function(data) {
$.each(data.posts, function(i,data) {
$('#logspan').replaceWith(data.logupdate);
});
});
}, 5000);
When I run the page, it works, but only ONE time and then it stops the interval completely (this is in Chrome and Firefox) and basically gives up.
This is weird, because there is yet another script which is running as follows and is doing its job perfectly:
var timer;
function startCount() {
timer = setInterval(count,1000);
}
function count() {
var el = document.getElementById('counter');
var currentNumber = parseFloat(el.innerHTML);
el.innerHTML = currentNumber+1;
}
I already tried to see if the first script works if I turned the second one off, but it is still no go. So, how can I ever make the first (JSON) script work? It is way past my bedtime thanks to this problem and I haven't gotten any step further!! pulls hair
Any suggestions / hints / tips are appreciated...
EDIT: Ok, I found something peculiar, when I replace the "replaceWith" and use "appendTo" it seems to update the #logspan just fine, but obviously I do not want to spam my own webpage. Maybe the problem lies somewhere else?
Agreed.
Use a different variable name than data in your $.each() function body, as you may be inadvertently referring to the data in the $.getJSON() function body
Since you're iterating over the posts returned in the JSON call, empty out the body of #logspan only once, then append the content of each post sequentially to #logspan.
var logbookTimer = setInterval(function () {
$.getJSON("php/log.php", function(data) {
// Empty out the body of the log
$('#logspan').empty();
// Add some content for each retrieved post
$.each(data.posts, function(i,d) {
$('<div>').html(d.logupdate).appendTo($('#logspan'));
});
});
},5000);
try this way
var logbook = function () {
$.getJSON("php/log.php", function(data) {
$.each(data.posts, function(i,data) {
$('#logspan').replaceWith(data.logupdate);
});
});
};
setInterval(logbook, 1000);
I have an issue when trying to get Javascript to execute functions in my desired order. I'm trying to get a jQuery modal form to load information based on a certain selection. I have two SELECT boxes that need to be loaded, but the contents of the second SELECT box depend entirely on the selected value of the first SELECT box.
I made the following functions to request the information I need:
function get_Subjects(varID, callback){
$.post("../vars/get_SID.php", { vid : varID },
function(result){
getInfo('tbsubjectdiv', '../vars/findSubjectlist.php?sid='+result);
});
callback();
}
function get_Selectedfields(varID, callback){
$.post("../vars/requestTblock.php", { vid : varID },
function(result){
populateForm('tbWiz', result);
document.form_tbWiz.varname.disabled = true;
$('.trSearch').hide();
$('.trValueset').hide();
});
callback();
}
function get_TextblockType(varID, callback){
$.post("../vars/requestVtype.php", { vid : varID },
function(result){
if(result == 0){ //Opzoeken
$('.trSearch').show();
}else if(result == 1){ //Datum vergelijken
$('.trSearch').show();
$('.trValueset').show();
}else if(result == 2){ //Percentage
//
}
});
callback();
}
The first function checks the MySQL database for the selected value
of the FIRST SELECT field, and loads the results into the second
SELECT field.
The second function requests the rest of the rest of the form data, and populates the form using populateForm(). It also hides
certain parts of my form in preparation for function three.
The third function basically requests which parts of the form have to be displayed, because that's not always the same.
The whole idea behind this is that I want to use populateForm() to populate all of the form fields. In order for populateForm() to properly set the selected SELECT option, the particular SELECT field must first contain the OPTION it needs to select. Makes sense. I try to make sure of this with my first function, which will load all of the OPTIONs. THEN I try to use the get_Selectedfields() to populate all the proper values. This is not what happens though. No matter what I try to do, getInfo() in the first function is ALWAYS being called LAST. This makes it impossible for populateForm() to select the proper option, which is driving me mad.
I'm trying to "force" the execution-order by doing this:
function getTextblock(var_ID){
get_Subjects(var_ID, function() {
get_Selectedfields(var_ID, function() {
get_Textblocktype(var_ID, function() {
// Done
});
});
});
}
When I realised it still did not work the way I wanted, I decided to use Chrome's Developer Tools to check the order in which everything is executed. It all works as expected, but at the very end it jumps straight back to getInfo(), which is part of the FIRST function I called. I'm absolutely clueless as to why getInfo() gets executed last. If this just gets executed at the very beginning, where I want it to execute, it would all work fine.
You have to call the callback in the callback function of the post request:
function get_Subjects(varID, callback){
$.post("../vars/get_SID.php", { vid : varID },
function(result){
getInfo('tbsubjectdiv', '../vars/findSubjectlist.php?sid='+result);
callback();
});
}
function get_Selectedfields(varID, callback){
$.post("../vars/requestTblock.php", { vid : varID },
function(result){
populateForm('tbWiz', result);
document.form_tbWiz.varname.disabled = true;
$('.trSearch').hide();
$('.trValueset').hide();
callback();
});
}
function get_TextblockType(varID, callback){
$.post("../vars/requestVtype.php", { vid : varID },
function(result){
if(result == 0){ //Opzoeken
$('.trSearch').show();
}else if(result == 1){ //Datum vergelijken
$('.trSearch').show();
$('.trValueset').show();
}else if(result == 2){ //Percentage
//
}
callback();
});
}
The POST is being handled asynchronously in your functions so your "callback" is really just being executed almost immediately after your initial call, whereas the callback of $.post is being executed after the post has occurred. Does that help you sort things out? You will probably need to kick off the rest of the process in the callback of $.post("../vars/get_SID.php", { vid : varID }...
$.post is shorthand for $.ajax so you can read up a bit more in the jQuery docs, but I would not suggest switching to synchronous requests. If you absolutely must have one request finished before the next can execute then kicking off that next step from the callback is the way to go.
You're using ajax. The first a is for asynchronous. If you called the functions from the function(result) blocks then they would occur in order.
Alternatively (and this isn't a great idea but you can do it) use the $.ajax() object and set async to false.
As you don't know how long long an ajax request will actually take, you can only chain events within the ajax response:
function getTextblock(var_ID){
$.post(YOUR_TARGET, YOUR_DATA, function(result){
YOUR_CODE
// CHAIN HERE, call new function or sub ajax request
});
}
Wesley,
The javascript will execute always on the predefined order. If you put a bunch of "alerts()" in the middle of your code, you can taste that.
But this is not true for callbacks, because they will be moved to the bottom of execution stack on javascript where we can't determine the order, since they are called by a AJAX return which by definition is asynchronous.
Even though your ajax executes in a millisecond, the callback will not be executed until all methods in your script block have finished.
You have, actually three options:
Chain all the methods sequence in callbacks. Please, don't call a callback!! It inst supposed to be you, but the "system" that will call those.
// The data you need first
function myStartPoint() {
$.post(url, function(result) {
// do what you need with this result (this is your callback, but anonymous)
// then, call the next step
secondPoint();
});
}
function secondPoint() {
$.post(url, function(result) {
// again, the callback is anonymous... your hardly need to declare something named callback
// chain how many points as you need
nextPoint();
}
}
"Force" the ajax to be synchronous with async:false option. This can cause performance issues.
The ugliest of all is to use the damned setTimeout which is very, very wrong, but will work in your case because, the setTimeout will put the method on the bottom of execution stack even after those callbacks which are expected to be fast. Seriously, I just put this option because eventually someone would say it... Do not take this path.
I am using jQuery for my Ajax calls... I have x amount of Ajax calls that append to a div. These Ajax load requests are generated by a PHP foreach loop... The problem is they render out of the order; they are set in the array...
<script type="text/javascript">
function loadPage(target, url, append)
{
if (append == true) {
$.get(url, function(data) { $(target).append(data) });
}
else {
$(target).load(url);
}
return false;
}
</script>
////// ----- PHP
<?php
$this->data['sidebar'] = array('login', 'active_leagues', 'latest_forum_threads', 'latest_matches', 'sponsors');
if (isset($sidebar[0]) && !empty($sidebar[0]))
{
echo '<div class="right_col">';
foreach($sidebar as $val)
{
echo "<script>loadPage('.right_col', 'http://dev.banelingnest.com/sidebar/". $val ."', true)</script>";
}
echo '</div>';
}
I am wonder if the cause of this is the web server responding slower to some requests than others... Other than that, I have no clue why this could be happening. Do you have any thoughts how I could keep the requests in order?
You have to create reference points before the requests, and append the results to them:
var counter = 0;
function loadPage(target,url,append)
{
if (append == true) {
var id = "container_"+counter;
$(target).append("<div id='"+id+"'></div>")
$.get(url, function(data) {
$("#"+id).append(data);
});
counter++;
} else {
$(target).load(url);
}
return false;
}
Your reference elements will be appended to the target on every loadPage() call, so they will be in the correct order, and the request can come in any order they will be loaded in their right place.
This is happening because the ajax calls are asynchronous, and the order they go out has nothing to do with the order they are returned. They will all happen independently and it's expected for some to run faster than others.
You will need to use $.ajax instead of $.get, and set async to false.
See this question: How can I get jQuery to perform a synchronous, rather than asynchronous, Ajax request?
You can also use the unique and interesting solution presented by #inti.
You could do synchronous requests instead of asynchronous, which'd force the browser to wait until each individual request finishes before starting the next. The downside that is for any "lengthy" requests (or many short ones), the browser will be locked up.
You may want to investigate sending all your requests in a single AJAX call, rather than doing one-request-per-call. That way it'd be easy for the scripts on both sides to keep everything in order. Otherwise you're stuck depending on the user link to your server having low error rates, low latency, and low congestion.
So instead of doing the equivalent of
loadPage(1); // fetch data #1
loadPage(37); // fetch data #37
loadPage(203); // fetch data #203
do something like
loadPage([1,37,203]); // fetch all 3 at once.
I have 2 ideas that may help, the first is:
jQuery has a $(document).ready(function() function that is possibly being called from a parent function or being inherited somehow, this means the JavaScript won't run before the rest of the PHP has loaded.
I have seen some functions inherit this from jQuery without it being declared.
The second is:
I am assuming that this function is running in the head or early on in your page and not the foot or later on in the document.
I hope they help.
This is the nature of AJAX, and yes the server is responding faster to some than others.
If you want them in order, you would have to make the first call, then on the complete event, call the next one, and so on; in essence creating a synchronous chain of calls (kind of goes against the A in AJAX).
Without knowing your specific reasons for wanting them in order, this may be a lot more work than what it's worth.
However you do it, it will take away from the user experience, because if one call is slow, all of the other will have to wait.
The simplest solution is creating placeholders, as inti described. Your elements will not necessarily appear in order, but they will end up in the right order. If you need them to appear in order too, here is a simple queue using deferreds:
var queue = [];
function loadPage(target,url) {
queue.push($.get(url));
$.when.call($, queue).then(function() {
$(target).append(Array.prototype.pop.call(arguments));
});
}
The AJAX calls will run in parallel, but the callbacks will fire strictly in order.
Here is what I did with the array or urls I needed to load in order.
I created the order of wrappers first, than did the ajax calls, and load the results into the matching wrapper. This keeps the calls asynchronous, but you still the the proper order.
$.fn.dashboarder = function(options)
{
var settings = $.extend({
urls: [],
}, options || {});
var self = this;
if (settings.urls.length)
{
$(self).html('');
/// create wrapper blocks in the proper order, so they eventually display in this order
$(settings.urls).each(function( index, value )
{
var wrapper = $( "<div />" )
.addClass('dashboard-block-item')
.attr('id', 'dashboard-block-item-'+index);
$(self).append($(wrapper));
});
$(settings.urls).each(function( index, value )
{
$('#dashboard-block-item-'+index).load(value, function( response, status, xhr )
{
}).delay(5000 * index);
});
}
return this;
}
function debug( obj ) {
if ( window.console && window.console.log ) {
window.console.log( obj );
}
};