【问题标题】:SSE loads lots of data and paralyzes AJAX post requestsSSE 加载大量数据并瘫痪 AJAX 发布请求
【发布时间】:2015-07-22 08:44:09
【问题描述】:

这是我的 sse_server.php 文件

include_once 'server_files/init2.php'; //this file includes the connection file to the database and some functions

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

$assocArray = array();

$fetch_article = $dbh->prepare("SELECT 
                                        article_author_id, 
                                        article_author_un,
                                        article_id, 
                                        article_cover,
                                        article_title,
                                        article_desc
                                    FROM articles ORDER BY article_id DESC");
$fetch_article->execute();

while ($fetch = $fetch_article->fetch(PDO::FETCH_ASSOC)) 
{
    $article_author_id    = $fetch['article_author_id'];
    $article_author_u     = $fetch['article_author_un'];
    $article_id           = $fetch['article_id']; 
    $article_cover        = $fetch['article_cover'];
    $article_title        = $fetch['article_title'];
    $article_desc         = $fetch['article_desc'];


    $randomNum = rand(0,500);

    //Insert the Random Number along with the article's info | Random Number as a Value and the contents as a Key
                $assocArray[
                            'randomNum'.'|'.                    //0
                            $article_author_id.'|'.             //1
                            $article_author_u.'|'.              //2
                            $article_id.'|'.                    //3
                            $article_cover.'|'.                 //4
                            $article_title.'|'.                 //5
                            $article_desc                       //6

                            ]  = $randomNum;
}

//sort the array
arsort($assocArray, 1); 
//echo '<pre>';
//print_r($assocArray);

//while(true){

    $var = '';
    foreach ($assocArray as $key => $value) {

        $var .=  $value .' => ' . $key . '`|||`<br>';
    }
    echo "retry: 6000\n";
    echo "data: {$var}\n\n";
    ob_flush();
    flush();

//}

这就是我在 client.php 文件中处理数据的方式

    <div id="feeds"></div>
    <script>

        if(typeof(EventSource)!=="undefined") {

            var eSource = new EventSource("sse_server.php");


            //detect message received
            eSource.addEventListener('message', function(event) {


            var jsV_feeds = event.data;
            var eventList = document.getElementById("feeds");


            var jsV_feedsArray = jsV_feeds.split('`|||`');  //Seperator



            eventList.innerHTML = jsF_ToFetch(jsV_feedsArray); 

            }, false);
        }
        else {
            document.getElementById("feeds").innerHTML="Whoops! Your browser doesn't receive server-sent events.";
        }


        function jsF_ToFetch(jsP_array) 
        {
            var string = ''; //an empty string 
            for (var i = 0; i < jsP_array.length-1; i++) 
            {

                jsV_Feed = jsP_array[i].split('|');

                jsV_randomNum           = jsV_Feed[0];
                jsV_article_author_id   = jsV_Feed[1];
                jsV_article_author_u    = jsV_Feed[2];
                jsV_article_id          = jsV_Feed[3];
                jsV_article_cover       = jsV_Feed[4];
                jsV_article_title       = jsV_Feed[5];
                jsV_article_desc        = jsV_Feed[6];


                string += jsV_randomNum +'<li><b>'+jsV_article_author_u+'</b><!--process the rest in a similar way--> </li>';


            } // for loop ENDS here
            return '<ol>' + string + '</ol>';
        }

    </script>

问题是,如果我只使用 foreach 循环,它会每 6 秒重新连接一次。
如果我将foreach 包装在while 循环中,它会保持连接处于活动状态,但会持续继续发送数据。这最终会在几秒钟内加载大量数据。它还使 AJAX Post 请求非常慢,同时通过另一个页面执行。

为什么会这样?
我怎样才能让它保持连接打开,不发送数据,也不减慢 AJAX 发布请求。

PS:我访问过这些链接 -
http://www.html5rocks.com/en/tutorials/eventsource/basics/
PHP Event Source keeps executing

可能是我对它们的理解不够好。如果它可以归结为更简单的术语,请这样做!

提前致谢!

【问题讨论】:

    标签: javascript php ajax pdo server-sent-events


    【解决方案1】:

    您想使用已在 sse_server.php 中注释掉的 while(true){} 循环。您的 SSE 脚本不应该退出(直到套接字关闭,这将在客户端发生,即您的 JavaScript 脚本关闭它,或者浏览器窗口被关闭)。

    您在使用 while 循环时遇到问题的原因是 while 循环内没有 sleep() 或等待操作。因此,您正在以最大速率向客户端发送数据(一遍又一遍地发送相同的数据!)。

    从概念上讲,我猜你想要的是这段代码:

    $lastID = 0;
    while(true){
      $fetch_article = $dbh->prepare("SELECT something FROM somewhere WHERE conditions AND articleID > ?");
      $results = $fetch_article->execute($lastID);
      if(has 1+ results) {
         foreach($results){
            echo result formatted for SSE
            $lastID = ...;
         }
         flush();ob_flush();
      }
      sleep(5);
    }
    

    这表示它将每 5 秒轮询一次数据库以获取 记录。如果没有新记录,它什么也不做——只是再睡 5 秒。但如果有新记录,它会通过 SSE 将它们推送给客户端。

    您可以调整 5 秒睡眠以在服务器上的 CPU 使用率和延迟之间找到平衡点。更短的睡眠意味着更低的延迟(您的客户端更快地获取新数据),但服务器上的 CPU 更高。

    旁白: 上面的lastID 方法只是检测您已经看到和尚未看到的记录的某种方式。如果您的表中有一个唯一的 ID,即AUTO_INCREMENT,那就太好了。但是,或者,如果使用created 时间戳插入数据库记录,则查询变为:

    $now = 0;
    while(true){
        $stmt = prepare( "SELECT ... AND created > ?" );
        $stmt->execute( $now );
        $now = time();
        ...process results ...
        sleep(5);
    }
    

    (稍微安全一点的是将$now设置为在结果中找到的最大created时间戳,而不是每次都设置为time();否则记录可能会从裂缝中溜走而无法发送给客户。)

    【讨论】:

    • 使用while 循环使connect'n 保持活动状态并且不会发送更多数据,但它会减慢从另一个页面执行的ajax post 请求。它还减慢了页面加载时间。 我是否必须在 while 循环中运行 SQL 查询以及我为对结果进行排序所做的所有处理,或者在它之外运行它是否可以?
    • @Devang 为什么使用 SSE?是不断地向客户推送数据库中的最新数据吗?如果是这样,数据库调用必须在 while 循环内。如果您想要的只是数据库的一次性快照,那么您应该使用简单的 ajax 轮询请求,而不是 SSE。
    • @Devang 至于它会减慢其他连接;除非您的 Web 服务器(或防火墙等)设置为将每个 IP 地址保持打开的套接字数量限制为非常低的数量,否则不应发生这种情况。 IE。如果您已经实施了我建议的更改,那么该套接字要么每 5 秒不发送任何内容,要么每 5 秒发送一小段数据。两者都不应该有足够的带宽来干扰其他套接字。 (我假设一个名为“articles”的表不会每 5 秒获得数百万甚至数百条新记录!)
    • 对,就是不断的向客户端推送数据库中的最新数据!就像 Twitter 一样。我现在正在使用 localhost,那可能是因为它吗?我可以在一页中使用多个 EventSource 对象吗?
    • 我按照您的建议执行此操作,这使连接保持打开状态并仅发送一次数据。我将在其中包含 SQL 查询。 $lastID = 0; $Length = count($assocArray); while(true) { $var = ''; foreach ($assocArray as $key =&gt; $value) { if($lastID &lt;= $Length){ $k = explode('|', $key); $var = $value .' =&gt; '.$lastID. '-' . $k[3] .' '.$k[5]. '|||&lt;br&gt;'; echo "retry: 6000\n"; echo "data: {$var}\n\n"; $lastID++; ob_flush(); flush(); } $var = ''; } sleep(5); }
    猜你喜欢
    • 2021-11-18
    • 2021-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-27
    • 2011-08-25
    相关资源
    最近更新 更多