如何在不使用setInterval/timeout的情况下检查实时更新?

11

我正在构建一个社交网络,尝试获取实时通知。当前,该网站使用setInterval每隔几秒钟发送一个AJAX请求,大致如下:

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);

这很完美,但我非常担心会导致服务器超载。我尝试了推送技术,但不知何故它发送的请求比上面的代码要多得多。

是否有其他更有用的技术可以实现实时数据推送?

编辑:为了实现长轮询,我使用了以下内容(使用了这里提到的示例: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
    });
})();

我可能无法正确理解彗星原理。

PHP 代码:

// 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
}

由于Facebook也使用PHP,他们是如何做到这一点的?


9
你或许想考虑使用WebSockets。 - Asad Saeeduddin
我不确定... 我该怎么做? - talhof9
你可以使用 set_time_limit 来设置脚本运行的最长时间限制。查看这个答案以了解 PHP 中长轮询的简单演示。 - Asad Saeeduddin
请问您能否发布您的PHP代码? - Asad Saeeduddin
我添加了一些 PHP 代码。 - talhof9
显示剩余2条评论
2个回答

9

你应该使用Websockets。你可以连接到服务器并注册onmessage处理程序。每当服务器有任何内容要发送给客户端时,你的处理程序就会被调用。无需超时。

检查你的浏览器是否支持Websockets。目前,只有Chrome,Opera和Safari支持它们。

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*/
}

连接中

var connection = new WebSocket('ws://example.org:12345/myapp');

处理程序

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);
}

文档: http://www.developerfusion.com/article/143158/an-introduction-to-websockets/

WebSockets是一种用于实现持久性连接的技术。传统的HTTP请求在完成后会关闭连接,而WebSockets允许客户端和服务器之间保持长时间打开的连接。这有助于构建实时应用程序,如聊天应用程序或在线游戏。


1
最近版本的Firefox支持套接字。 - Asad Saeeduddin
2
FYI,IE10也支持 WebSocket。 - sdespont
@sdespont 这是个好消息... 你知道 Hixie 是否被支持了吗? - ATOzTOA
这在WAMP上运行得很好,但是上传到服务器后,由于socket_bind()行的原因,我一直收到“地址已在使用”的错误。尝试了“SO_REUSEADDR”方法,仍然没有运气。我一遍又一遍地搜索谷歌,但找不到解决方案。有什么想法吗? - talhof9
你是什么意思?如果你是指进程终止器,我有一个。我现在正在使用Bluehost。 - talhof9
显示剩余5条评论

3

一旦WebSocket在主要浏览器中得到更广泛的实现,它将成为未来发展的方向——我想至少需要5年时间。

据我所知,Facebook聊天使用Comet和大量服务器。如果您想要更轻量级的解决方案,我可以想到两个选项。

  1. 减少轮询间隔。这严格是一个UI问题 - 用户可能会对几分钟之类的间隔有完全可接受的体验。确切的最佳间隔是通过用户测试来确定,但每5秒轮询可能有点过度了。无论您选择什么作为最佳间隔,这都为您提供了一种快速扩展的方法,只需增加时间间隔,直到服务器停止崩溃即可。

  2. 使用HTTP验证缓存。如果服务器仅在内容与上次请求不同时返回响应正文,则可以使请求更轻量化。您将不得不使用ETag或Last-Modified标头以及服务器上的轻量级修改检查系统构建自定义内容,但这可能会为您节省一些字节。


五年过去了,正如我所希望的那样,每个主要浏览器都原生支持WebSockets。我在GitHub上编写了一个最简单的示例https://github.com/chrisbroski/bare-socket。 - Chris Broski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接