Good day everyone.
Recently, I thought about the issue of background information update, and I came up with one idea.
The essence of the task - we are on the news list page. It is necessary to update the list as new news becomes available. PHP server language
')
Consider the classic version through constant requests by Ajax:
1) The client sends an AYAX request to the server, for example, to the address - / ajax / get_upades & time = xxxxxx
2) PHP looks at whether there are records in the database that are newer than time.
3) If there is, selects them and returns
4) If there is nothing returns
In this case, we are forced to constantly jerk PHP and DB to answer the question, is there any new data?
I really did not like this idea.
I also didn’t like the variants with long polling due to various difficulties of implementation and keeping a large number of open connections.
Then I decided why not to shift the task of determining the availability of new data to the server itself, completely bypassing PHP
The essence of the idea is as follows.
The client constantly pings an empty file marker. Let's call it / ping / new_news
When a file is returned, the server sends a header - ETag of the form “10aa0f-7-4b877e2d4941c”. This is one of the headers involved in the caching mechanism. ETag is calculated based on the inode, size and mtime information of the file. Those. when changing mtime (file modification time), the server will send another ETag.
When we insert a new news, all we need is to update the mtime file, for example, touch (), and it is better to create a trigger in the database to insert a record and change the file
Next, we write a small class. Let's call it Updater
var Updater = function(){ this.params = { period: 3000, url: '', onModified: function(data,x,modified){}, bgPause: false }; this.interval = null; this.ETag = ''; this.lastModified = ''; this.init = function(params){ var me = this; this.params = $.extend(this.params, params); if(this.params.bgPause){ $(window).blur(function(){ me.pause() }); $(window).focus(function(){ me.resume() }); } }; this.start = function(){ var me = this; this.interval = setInterval(function(){ me.doUpdate() }, this.params.period); }; this.doUpdate = function(){ var me = this; $.ajax(this.params.url, { success: function(data,status,x){ if(me.ETag != x.getResponseHeader('ETag')){ me.params.onModified(data,x,me.lastModified); me.lastModified = x.getResponseHeader('Last-Modified'); } me.ETag = x.getResponseHeader('ETag'); }, beforeSend: function(x){ if(me.ETag != '') { x.setRequestHeader('If-None-Match', me.ETag); } }, cache: false }); }; this.pause = function(){ clearInterval(this.interval); this.interval = null; }; this.resume = function(){ if(this.interval != null) return; this.start(); }; };
In the cycle, the script sends requests to the specified URL, when an Etag change is detected, the onModified task is called to send the request to receive the data itself.
Sometimes Apache after changing the pinged file, continues to give the old Last-Modified and ETag for some time. Adding the cache false option to the request request cures this situation
To reduce the number of requests we stop pinging the server when the user does not see our page.
if(this.params.bgPause){ $(window).blur(function(){ me.pause() }); $(window).focus(function(){ me.resume() }); }
Here is such an idea came to mind. I will listen to your criticism, ideas, suggestions. Thanks to all
UPD. Added parameter beforeSend to AYAX request