Building a social network, I'm trying to fetch live notifications. Currently, the site sends an AJAX request every few seconds using setInterval. It looks something like this:
setInterval ( function(){
url = base_dir+"/ajax/file.php";
data = "data=someData";
$.ajax({
type: "POST",
url: url,
data: data,
dataType: "json",
beforeSend: function(x) {
if(x && x.overrideMimeType) {
x.overrideMimeType("application/json;charset=UTF-8");
}
},
success: function(JSON){
// retrieve data here
}
});
}, 5000);
That works perfectly, but I'm very worried about that creating servers overload. I tried the comet technique but for some reason it sends much more requests than the above code.
Is there any other more useful technique for pushing this data live?
EDIT:
For implementing long polling I used the following (used the example mentioned here: http://techoctave.com/c7/posts/60-simple-long-polling-example-with-javascript-and-jquery):
(function poll(){
url = base_dir+"/ajax/file.php";
data = "data=someData";
$.ajax({
type: "POST",
url: url,
data: data,
dataType: "json",
beforeSend: function(x) {
if(x && x.overrideMimeType) {
x.overrideMimeType("application/json;charset=UTF-8");
}
},
success: function(JSON){
// retrieve data here
},
complete: poll,
timeout: 5000
});
})();
There's a possibility that I might not get the comet principle right.
PHP code:
// Checks for new notifications, and updates the title and notifications bar if there are any
private static function NotificationsCounter (){
//self::$it_user_id = query that retrieves my id for further checks;
//$friend_requests_count = query that retrieves the friend requests count;
//$updates_count = query that retrieves the updates count;
$total_notifications = $friend_requests_count+$updates_count;
if ($total_notifications > 0) $addToTitle = "(".$total_notifications.")";
else $addToTitle = "";
if ($updates_count > 0) $counterHTML = "<span class='notification_counter' id='updates_counter' style='float: right;'>".$updates_count."</span>";
else $counterHTML = "";
$data = array("counter"=>$total_notifications,"addToTitle"=>$addToTitle,"counterHTML"=>$counterHTML,);
echo json_encode($data); // parse to json and print
}
Since Facebook uses PHP as well, how do they do it?
You should use websockets. You can connect to the server and register onmessage handler. Whenever the server has anything to be send to client, your handler will get invoked. No timeout needed.
Check for websocket support in your browser. As of now, only Chrome, Opera and Safari support them.
if ('WebSocket' in window){
/* WebSocket is supported. You can proceed with your code*/
} else {
/*WebSockets are not supported. Try a fallback method like long-polling etc*/
}
Connecting
var connection = new WebSocket('ws://example.org:12345/myapp');
Handlers
connection.onopen = function(){
console.log('Connection open!');
}
connection.onclose = function(){
console.log('Connection closed');
}
connection.onmessage = function(e){
var server_message = e.data;
console.log(server_message);
}
Documentation: http://www.developerfusion.com/article/143158/an-introduction-to-websockets/
Websockets will be the way to go once they are more universally implemented across the major browsers - I would guess a minimum of 5 years.
The last I heard Facebook chat uses comet and a whole bunch of servers. If you want something more lightweight I can think of two options.
Reduce the polling interval. This is strictly a UI issue - users may have a perfectly acceptable experience with intervals as long as a couple minutes. The only way to know for certain is through user testing, but polling every 5 seconds is probably overkill. No matter what you choose as the optimal interval, this does give you an quick way to scale if you are getting hammered - just crank up the interval until the servers stop melting.
Use HTTP validation caching. You can make the requests more lightweight if the server only returns a response body when the content has changed since the last request. You will have to build something custom using ETag or Last-Modified headers and a lightweight modification checking system on the server, but it might save you a few bytes.
Related
I have searched a lot but no solution worked for me.
I'm working on a captive portal with pfsense that means a user will need to fill out a form whenever they connect to our network before they recieve free internet. What I'm doing is taking some data from user and making an ajax Get request (using jQuery 3.2.1) to a web service (based on asp.net web api).
Everything works fine when I do it on a computer although it doesn't work on mobile browsers.
I don't know why but somehow data doesn't go to web services when we use mobile phones.
This is my javascript code.
function uploadData(){
var PhNumber = document.getElementById("customerPhone").value;
var cName = document.getElementById("customerName").value;
var Url="http://192.168.1.155/customer/api/Values?customerName="+cName+"&customerPhone="+PhNumber+"";
var exp = /^((\+92)|(92)|(0092))-{0,1}\d{3}-{0,1}\d{7}$|^\d{11}$|^\d{4}-\d{7}$/;
var cNum = exp.test(PhNumber);
if (exp.test(PhNumber)) {
$(function () {
$.ajax({
type: 'GET',
url : Url,
cache : 'false',
dataType:'xml',
success: function (responce) {
return alert("Data Saved");
},
failure: function() {
alert("Some Error Acured");
}
});
});
}
}
So I'm having a database which gets updated after getting score of a match.
Right Now I'm able to make ajax get request to my route for getting the latest score from database on $(document).ready(function() and change my html to show score but it is static and does not gets updated.
So my question is how to make this ajax request in a loop. Right now a user has to refresh to make the request again and get the updated latest score.
I am using mongoose, mongodb, nodejs on express framework, and jquery for scripts.
This is my nodejs route for handling ajax request, it returns json of match data
router.get('/matchData',function(req,res){
Match.getMatchData(function(err,match){
if(err) throw err;
res.send(match);
});
});
This is my script for AJAX.
$(document).ready(function(){
$.ajax({
type: 'GET',
url: 'http://localhost:3000/matchData',
dataType: 'json'
})
.done(function(data) {
$('.team1').text(data.title);
$('.team1odds').text(data.values.t1odds);
$('.team1probability').text(data.values.t1probability);
$('.team1score').text(data.values.t1predict);
$('.team2').text(data.title);
$('.team2odds').text(data.values.t2odds);
$('.team2probability').text(data.values.t2probability);
$('.team2score').text(data.values.t2predict);
})
.fail(function() {
alert("Ajax failed to fetch data")
});
});
There are multiple ways to do this, the easiest would be to use long polling, but it is also the most ineffective.
Very simple example:
var seconds = 5;
setInterval(function runner() {
// run your ajax call here
var result = callAjax();
}, seconds * 1000);
A much better way would be to use websockets, as the score gets updated server-side you push the event to the client.
I'm building a news app. I refresh a div with the class of .new_feed every 10 seconds, to check for new updates, and when there is it shows up. Now the problem is, when there is a new feed in it, and the 10 seconds is up, and you don't click to see, and wait for 40 seconds before you click,it brings up 4 records instead of 1. I think the problem has to do with caching.
Refresh script that gets the headline of the news
$(document).ready(function() {
$.ajaxSetup({ cache: false });
setInterval(function() {
$('.new_feed').load('headline.asp');
}, 10000);
});
Getting the feeds
$(function() {
//More Button
$('.more2').live("click",function() {
var u_pic_id = $(this).attr("id");
if (u_pic_id) {
$("#more2"+u_pic_id).html('<img src="moreajax.gif" />');
$.ajax({
type: "POST",
url: "show_more.asp",
data: "lastmsg="+ id,
cache: false,
success: function(html) {
$("ol#updates2").append(html);
$("#more2"+id).remove();
}
});
}
return false;
});
});
</script>
HTML
<div id="more2<%=(rs_ncount_id.Fields.Item("id").Value)+1%>" class="morebox2">
<a href="#" class="more2" id="<%=(rs_ncount_id.Fields.Item("id").Value)+1%>">
Load New Feeds
</a>
</div>
Using HTTP header
You have to set the Cache-Control HTTP/1.1 header at the server side. This is the recommended approach.
Using a nonce in the request
However you can also use a hacky solution, if you can't change the server settings. Use a nonce in the request:
$('.new_feed').load('headline.asp?' + nonce);
Because it will look like a different request to the browser, it will ignore the cached value.
The simplest solution for a nonce is using the current time:
var date = new Date();
var nonce = date.getMilliseconds();
I had an answer written up that pointed out the cache:false option for $.ajax but upon reviewing your OP I realized you were already using it. The documentation indicates the cache:false option will only append a timestamp on GET requests (and POST requests for IE8).
Since you're using a POST its unlikely the cache:false option is actually going to help (unless you're using IE8?). Instead, like #meskobalazs states you'll need to create and append a nonce.
One way to implement this might be like:
function getValues(id) {
var url = 'myUrl?id=' + id;
$.ajax({
type: "POST",
url: url + '&_=' + (new Date()).getTime()
}).done(function(response) {
// do stuff
})
}
Of course if you have access to the server the appropriate way to handle this would be to correctly set the response headers. You may also consider using a more RESTful approach where the GET verb and route is used to request data.
I am developing a Twitter web app for myself. I am retrieving the latest trending topics.
Here's how I'm doing it:
$.ajax({
url: 'http://api.twitter.com/1/trends/1.json',
dataType: 'jsonp',
success: function(data){
$.each(data[0].trends, function(i){
$('div#trending').hide().append("<p><a href='"+data[0].trends[i].url+"'>"+data[0].trends[i].name+"</a></p>").fadeIn(1000);
//Cache into LocalStorage
localStorage["trending"+i] = data[0].trends[i].name; //Name
localStorage["trendurl"+i] = data[0].trends[i].url;//URL
});
}
});
But sometimes while I am developing it, the rate limit is exceeded.
How can I detect if the rate limit has been exceeded?
I cannot seem to detect if this error is being shown:
{"error":"Rate limit exceeded. Clients may not make more than 150 requests per hour.","request":"\/1\/trends\/1.json"}
I have tried it by:
success: function(data){
if(data[0].error != 'undefined'){
//load localstorage cache
}
}
But that doesn't seem to work.
Please help.
Thanks :)
The Twitter API sends a HTTP 400 status code when you are rate limited, so check for that:
$.ajax({
// ...
statusCode: {
400: function() {
alert( 'rate limited.' );
}
}
});
Also note that your comparison is a bit wrong. data[0].error != 'undefined' will always yield true when the error text is not 'undefined'. So even when you are rate limited, the error text won’t be 'undefined' and as such succeed. What you probably want to check is this:
if ( !data[0].error ) { // data[0].error is not null
// ...
}
try something like $.ajax({..}).fail(function(){});
i.e.
$.ajax({..})
.done(function() { alert("success"); })
.fail(function() { alert("error"); })
.always(function() { alert("complete"); });
and let me know how this works now.
cheers,
/Marcin
If you're not making an OAuth call, you'll be rate limited to 150 calls per hour. But, there's a small work-around which has worked for me.
According to the Twitter page on Rate Limiting (http://dev.twitter.com/docs/rate-limiting), "Rate limits are applied to methods that request information with the HTTP GET command. Generally API methods that use HTTP POST to submit data to Twitter are not rate limited, however some methods are being rate limited now."
Since the default type of an AJAX call is 'GET', try explicitly changing your type to 'POST' like this:
$.ajax({
url: 'http://api.twitter.com/1/trends/1.json',
type: 'POST',
dataType: 'jsonp',
success: function(data){
$.each(data[0].trends, function(i){
$('div#trending').hide().append("<p><a href='"+data[0].trends[i].url+"'>"+data[0].trends[i].name+"</a></p>").fadeIn(1000);
//Cache into LocalStorage
localStorage["trending"+i] = data[0].trends[i].name; //Name
localStorage["trendurl"+i] = data[0].trends[i].url;//URL
});
}
});
Hope this helps!
James
I am serving my website from mywebsite.com. I host images on flickr so all images are loaded in the user's browser via get requests to flickr. Many of my websites users access mywebsite.com from corporate networks, which block access to flickr.com. This means users get very annoying blank placeholders instead of the images. I get the same problem with the Facebook like button. This makes my site look very unattractive to such users.
Is there a way I can run a client side script which will check if flickr.com, facebook.com, etc. are accessible. If not I could change the href attribute of the image to load from an alternate source, or replace with a standard image explaining that their network is blocking access. I could also remove the Facebook like button.
I thought an XML http request would do the trick, but then I'd hit cross domain issues I think. I guess I could also set up a proxy to serve the images, but I don't want to do that; the idea of this is that flickr takes the bandwidth hit.
TLDR: How do I determine if flickr.com is accessible from a user's browser, using client side technology.
You could try this...
var image = new Image();
image.onerror = function() {
var images = document
.getElementById('flicker-images')
.getElementsByTagName('img');
for (var i = 0, imagesLength = images.length; i < imagesLength; i++) {
images[i].src = 'images/flickr_is_blocked.gif';
}
};
image.src = 'http://flickr.com/favicon.ico';
Hacky, but it seems to work. However it relies that the favicon.ico 404ing means the main site is.
jsFiddle.
Working example: http://jsfiddle.net/peeter/pW5wB/
JS:
$(document).ready(function() {
var callbackOnSuccess = function(src) {
alert("Successfully loaded " + src);
return false;
};
var callbackOnFailure = function(src) {
alert("Failed loading " + src);
// Here you can do whatever you want with your flickr images. Lets change the src and alt tags
$(".flickr").attr("src", "flickr_is_blocked.gif");
$(".flickr").attr("alt", "Flicker is blocked");
// Lets change the parents href to #
$(".flickr").parent().removeAttr("href");
return false;
};
checkAvailability("http://flickr.com/favicon.ico", callbackOnSuccess, callbackOnFailure);
});
function checkAvailability(src, callbackSuccess, callbackFailure) {
$("<img/>").attr("src", src).load(function() {
callbackSuccess(src);
}).error(function() {
callbackFailure(src);
});
}
HTML:
<a href="http://flickr.com/favicon.ico">
<img class="flickr" src="http://flickr.com/favicon.ico" alt="Flickr"/>
</a>
For facebook you can simply include the Facebook JS API and then test if one of the objects/functions it exports exists.
It would be better if you did not (ab-)use external hosts for your stuff. If you want a CDN, better use a real one...
Flickr and Facebook both have APIs that support JSONP, so cross-domain isn't an issue.
i.e. Here's a request that just echoes some dummy data from flickr's API.
$.ajax({
url: "http://www.flickr.com/services/rest/?jsoncallback=?",
dataType: 'json',
data: {method: "fickr.test.echo", format: "json", api_key: "02de950d65ec54a7a057af0e992de790"},
success: callback
});
You can't reliably set error handlers on a jsonp reqest, so show a "loading" image until that success callback gets called. Set some timeout that will show an error message if the response doesn't come back fast enough.
This works, but timeout must be set!
$.ajax({
url: "http://example.com/ping.html",
type: 'GET',
dataType: 'jsonp',
jsonpCallback: 'jsonCallback',
timeout: 1000,
cache: false,
success: function(response) {
console.log("SERVER UP!");
},
error: function(e) {
console.log("SERVER DOWN!");
}
});
ping.html should return:
jsonCallback({response:'PONG'});