What is the best practise to create a notification services such as in facebook website? - facebook

What is the best practise to create a notification services such as in facebook website. I see it is noy good to make a http request periodically to check if there is updates on the server or not.

This is calling long polling (type of an AJAX).
I'll try to describe a situation where you use PHP and JS, as Facebook does.
You send an AJAX request to the server.
Infinite loop starts on the server side
<?php
$seconds = 0;
while(true) {
if ($seconds >= 55) {
die("no_notifications");
}
if (false !== ($notifications_json = getNotifications()) {
echo $notifications_json;
die();
}
$seconds++;
sleep($TIME_TO_WAIT_BEFORE_NEXT_CHECK); //this number should be based on your performance
}
?>
When there's a new notification, script die() s and response is handled by javascript
New request is sent to the server, again, waiting to new notifications
With javascript (I'll show you an example with jQuery), you can use something like
$(function() {
pollForNotifications();
});
function pollForNotifications() {
$.get("/notifications", function(response) {
if (response != "no_notifications") {
alert("You've got one new notification!");
//more proccessing here
}
pollForNotifications();
});
}
Remember that there are time limits in specific browsers to complete the request! You SHOULD die() after some amount of time (55 seconds) even if you don't have any notifications, to prevent troubles (this prevention is included in script above)!

You could use the WebSocket api for a real push service (not ajax polling). But it is part of HTML5 and not supported by all browsers and web servers at the moment.

You might want to check out Pusher. It'll handle pushing notifications and supports many browsers.

Related

How to control if PWA uses cached version or fetches latest version?

I have installed my PWA from Chrome and Firefox on Android, and from Safari on iOS. When I update my code on the website, I see quite different behaviour in the PWAs in terms of using older cached versions vs the newest one - Firefox-created PWA seems to require about 2-3 kill and restarts of the PWA, Chrome takes 5-6, and I couldn't get Safari-based PWA to start showing the newest version without deleting the PWA and re-adding to Home Screen from browser.
Is there a spec that defines the conditions under which a newer, non-cached version is fetched? After much reading, I disabled the registering of my service worker, which should have made the PWAs network-only (no service-worker cache) but I continue to get old versions of the site served up in the PWAs. A normal browser window also seems to require multiple deep refreshes to get the new version, so I assume there is something besides the service worker that determines this?
Consider the following code.I will break it in parts:
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request).then(
function(response) {
// Check if we received a valid response
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// IMPORTANT: Clone the response. A response is a stream
// and because we want the browser to consume the response
// as well as the cache consuming the response, we need
// to clone it so we have two streams.
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
});
Over here cached first strategy is used,whenever you reload the page a fetch event is triggered.
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
First it checks if the required request is available in the cache,if yes then it will return the response and won't fetch from network.
return fetch(event.request).then(
function(response) {
// Check if we received a valid response
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// IMPORTANT: Clone the response. A response is a stream
// and because we want the browser to consume the response
// as well as the cache consuming the response, we need
// to clone it so we have two streams.
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
Now if the file was not present in the cache then this block gets to network gathers the required files then respond with it an also save it to cache for further use.
Consider the case that you have a file sample.html and it is cached,now you make some changes to the file's code but the changes won't be seen on your browser because it will see that the sample.html(old) was already present in the cache and respond with it.
Few generalized considerations regarding SW and PWAs:
Once you register your Service Worker (SW), you have to un-register it to make it sure you get the latest/updated version, and you can do so in the application tab under service worker
and then
to make sure you get the latest/update version of you PWA. What else you can do on top of it is, you can change the object name of the cache storage like below:
.
As long as you keep the object name same as well as don't unregister the SW and clear the Cache storage either, you will have to refresh your website. There is also, hard reload/clear cache and hard reload option as well if you keep pressing the refreshing button of the browser for couple of seconds but it still doesn't work until you unregister your service worker. So, in short unregistering SW and clearing Cache storage manually or changing the name of the Cache storage object will do the trick. Like any other technology/asset there are pros and cons. This is one of the draw back of the PWA if we don't use it properly, your client will never get the latest version, or the time he will get it may be too late. Cheers:)

FF Addon SDK page mod script to content script communication not working

For starters, I've been trying to allow communication from a page script to a content script. If the docs are accurate, this should be easy. Here's what I'm doing, I believe fully in accordance with https://addons.mozilla.org/en-US/developers/docs/sdk/latest/dev-guide/guides/content-scripts/communicating-with-other-scripts.html#Using%20the%20DOM%20postMessage%20API :
And here's my live test case:
main.js:
exports.main = function() {
var data = require('sdk/self').data,
pageMod = require('sdk/page-mod');
pageMod.PageMod({
include: '*',
contentScriptFile: data.url('postMessageRelay.js'),
});
};
postMessageRelay.js
// Trying with window.addEventListener also doesn't work
document.defaultView.addEventListener('message', function (e) { // e.data, e.origin
console.log('would be good if it got here:'+e.data);
});
console.log('it gets here at least');
And the JavaScript within a regular HTML file (on a normal remote server, not file or localhost):
try {
window.postMessage('webappfind', window.location.href);
}
catch(e) {
alert(e);
}
This really looks like either a full-blown bug for this functionality or a problem with the docs... I had similar problems trying to communicate via custom events so going a little bananas...
Answered in Bug 910972, but leaving it here to for future visitors of SO:
The issue was with the page immediately firing postMessage in the head tag, so the page-mod script isn't even yet attached to the page to listen to the message event. The communication back and forth between page and content scripts as in this example works as long as this timing is taken into consideration

Redirect after user has logged in

I'm pretty new to Angular, and right now I'm just trying to get all my routes set up and working as I'd like.
Setup:
When a user navigates to certain pages (/settings for this example) the app should check if there is a user already logged in. If there is continue as usual. Otherwise the user should go to the login page (/login).
What I'd like:
After the user has successfully logged in they should go to the page they were originally trying to get to (/settings)
My question:
Is there an "Angular way" to remember where the user was trying to go to?
Relevant code:
app.js
.when('/settings', {
templateUrl: '/views/auth/settings.html',
controller: 'SettingsCtrl',
resolve: {
currentUser: function($q, $location, Auth) {
var deferred = $q.defer();
var noUser = function() {
//remember where the user was trying to go
$location.path("/login")
};
Auth.checkLogin(function() {
if (Auth.currentUser()) {
deferred.resolve(Auth.currentUser());
} else {
deferred.reject(noUser());
}
});
return deferred.promise;
}
}
})
login.js
$scope.submit = function() {
if(!$scope.logInForm.$invalid) {
Auth.login($scope.login, $scope.password, $scope.remember_me)
//go to the page the user was trying to get to
}
};
Much thanks to John Lindquist for the video which got me this far.
First off, you do not want to redirect the user to a login page.
An ideal flow in a single page web app is as follows:
A user visits a web site. The web site replies with the static assets for the
angular app at the specific route (e.g. /profile/edit).
The controller (for the given route) makes a call to an API using $http, $route, or other mechanism (e.g. to pre-fill the Edit Profile form with details from the logged in user's account via a GET to /api/v1/users/profile)
If/while the client receives a 401 from the API, show a modal to
login, and replay the API call.
The API call succeeds (in this case, the user can view a pre-filled Edit Profile form for their account.)
How can you do #3? The answer is $http Response Interceptors.
For purposes of global error handling, authentication or any kind of
synchronous or asynchronous preprocessing of received responses, it is
desirable to be able to intercept responses for http requests before
they are handed over to the application code that initiated these
requests. The response interceptors leverage the promise apis to
fulfil this need for both synchronous and asynchronous preprocessing.
http://docs.angularjs.org/api/ng.$http
Now that we know what the ideal user experience should be, how do we do it?
There is an example here: http://witoldsz.github.com/angular-http-auth/
The example is based on this article:
http://www.espeo.pl/2012/02/26/authentication-in-angularjs-application
Good luck and happy Angularing!

using the facebook javascript sdk with a web worker

I have a Facebook application that needs to query a lot of data from the Graph API. I can currently pull all of the data using the Facebook javascript-sdk, however the user has to wait for facebook to return the query every time (.5-1.0 seconds). I wanted to put this functionality in a javascript web worker so that it will continuously run in the background pulling the data and storing it in a javascript array for when the user needs it.
I am new to javascript web workers but I know that they have limitations that prevent them from accessing the following:
The DOM (it's not thread-safe)
The window object
The document object
The parent object
Do these limitations prevent me from being able to load the Facebook Javascript-SDK in my web worker and use it to make calls?
Also, I tried using: importScripts("http://connect.facebook.net/en_US/all.js"); as an alternative way to load the script it gave me a "Uncaught Undefined" Error.
Currently I have my web worker passing data to and from my page (including the user access token) but I do not know how to make api calls without the SDK.
Note: My application is using only javascript, has no database and no back end server code (php, ruby, etc). I need to keep it this way.
When you connect to the Facebook SDK you should receive an accessToken in the response.
FB.Event.subscribe('auth.authResponseChange', function(response) {
if (response.status === 'connected') {
var accessToken = response.authResponse.accessToken;
}
});
Send this accessToken to your Web Worker:
var myWorker = new Worker(url);
myWorker.sendMessage({accessToken:accessToken});
Now you can use XMLHttpRequest and the Facebook graph api (inside the web worker):
//inside your worker
onmessage = function (oEvent) {
var accessToken = oEvent.data.accessToken;
if(accessToken){
function loaded(){
var fbResponse = this.responseText;
postMessage({fbData: fbResponse});
}
var xhr = new XMLHttpRequest();
xhr.onload = loaded;
if (xhr != null) {
xhr.open('get', 'https://graph.facebook.com/me?type=normal&method=GET&access_token='+accessToken, true);
xhr.send();
}else {
postMessage({error: 'XHR not supported'});
}
}else{
postMessage({error: 'No access token'});
}
};
curl http://connect.facebook.net/en_US/all.js -s | grep "document" -q && echo "Nope."
Just so you don't have to actually execute this: it will print "Nope."
Sorry.
That said: you should check out the async flag on XMLHttpRequest.open.

Is it possible to do non-blocking Facebook API calls, using node.js?

I want to use node.js to boost my Facebook applications performance. Imagine application that tries to compute who is you best friend on Facebook, fetching a lot of data from API calls - determining how many times your friends have posted to your wall, how many photos you have marked on together - so on.
So instead of running that calls one after one, as I do using PHP I have an idea to send them all together to Facebook using non-blocking, asynchronous nature of Node.js.
So overall execution time will be the time of most time consuming API call, but not the sum of execution time of the every call, right?
I try to use node-facebook-sdk (https://github.com/tenorviol/node-facebook-sdk) to make Facebook API calls and it seems to be that it's blocking, isn't it?
Just quick and dirty modification of example code, requesting 3 user profiles, seems that calls are not asynchronous, each sending to Facebook after previous has completed. Are there any way to avoid that?
Thank in advance!
var fbsdk = require('facebook-sdk');
var facebook = new fbsdk.Facebook({
appId : '_APPID_',
secret : '_SECRET_'
});
var i = 0;
setInterval(function() {
i++;
console.log("TICK " + i);
}, 500);
facebook.api('/100000997949108', function(data) {
console.log(data);
});
facebook.api('/1609464095', function(data) {
console.log(data);
});
facebook.api('/100000560820400', function(data) {
console.log(data);
});
This library will help you out with all things async. I hashed the particular method you would want to use for your problem, but the library as a whole is excellent at abstracting some of the more tedious (and ugly!) async patterns away. Great transitioning tool for those coming from procedural and you can take a peak under the covers if you want to learn some async patterns.
https://github.com/caolan/async/#parallel