jQuery Long Polling(使用PHP服务器端)

时间:2012-07-02 15:50:36

标签: php jquery ajax json getjson

我在这里做了一个噩梦,所以任何帮助都将非常感激!首先,我将解释我正在尝试做什么:

我正在尝试使用Yii框架在我的localhost MAMP服务器上实现这里描述的系统:https://stackoverflow.com/a/1086448/1034392。我有一个函数来检查数据库中是否有任何新通知 - 如果有,它会解析它们并且json对它们进行编码。我每隔5秒就调用一次while循环函数。

所以:转到/ user / unreadNotifications会触发以下

    Yii::log('test'); // to check it's getting called  

    $this->layout=false;

    header('Content-Type: application/json');

    // LONG POLLING 
    while (Yii::app()->user->getNotifications() == null) {
        sleep(5);
    }

    echo Yii::app()->user->getNotifications(); // prints out json if new notification

    Yii::app()->end();

    return;

这很好用 - 去了浏览器中的链接并验证了json响应 - 一切都很好。

然后我尝试了各种各样的jQuery来让它工作......我发现工作的唯一方法是使用类型为POST的$.ajax,但只有当有等待通知时(所以有些json是回)。 $.get$.post被“中止”(显示在firebug中)但是URL被调用(因为我可以看到日志文件已更新) - 奇怪。

我使用$.get的原始设置是:

        <script type="text/javascript">
            function notificationPoll() {
                $.get('<?php echo Yii::app()->createUrl('user/unreadNotifications') ?>','', function(result) {
                    $.each(result.events, function(events) {
                        alert('New Notification!');
                    });
                    notificationPoll();
                }, 'json');
            }
        </script>

        <script type="text/javascript">
            $(document).ready(function() {
                $.ajaxSetup({
                    timeout: 60 //set a global ajax timeout of a minute
                });
                notificationPoll();
            });
        </script>

由于某种原因,这只是“中止”。我已尝试使用'jsonp',即使它不是CORS请求..但这也不起作用。

似乎无法随处获得!任何人都可以参与进来吗?

非常感谢

4 个答案:

答案 0 :(得分:3)

您必须确保该功能在合理的时间内终止。你能做的是:

$ttl = 10;
while ($ttl--) {
    $json = Yii::app()->user->getNotifications();
    if (null != $json) {
        break;
    }
    sleep(1);
}
if (null == $json) {
    $json = json_encode(array(
        'nothing' => true
    ));
}
header('Content-Type: application/json');
echo $json;

Yii::app()->end();
return;

使用setInterval()将轮询功能设置为计时器。现在每隔10秒钟调用一次该函数,您可能需要设置一个信号量以避免在上一次迭代返回之前调用它:

var timer = setInterval(
    function() {
        if (this.calling) {
            return;
        }
        var fn = this;
        fn.calling = true;
        $.post(url)
         .done(function(data) {
            ..
         })
         .always(function() {
            fn.calling = false;
         });
    },
    10000
);

然后AJAX中的轮询函数需要检查(在.done())回调中通知是否存在:

function(data) {
    if (data.hasOwnProperty('nothing')) {
        alert('No notifications');
        return;
    }
    console.log(data);
    ...
}

现在一个重要的事情是您的通知是什么样的。在这里,我假设它是一个JSON编码的字符串。但是如果它是Yii函数返回的数组或对象,则需要处理其编码。这可能更清晰,没有任何IF:

header('Content-Type: ...
die(json_encode(
    array(
        'status'         => 'success',
        'notification'   => $json /* This is NULL or an array */
    )
    // Javascript side we check that data.notification is not null.
));

解码已经由jQuery处理,因此变量&#34; data&#34;上面已经是一个Javascript对象,你不需要调用JSON.parse 。您可以检查data 对象,并且它具有预期的属性。这会警告你任何错误。

要处理到另一个页面的导航,您可以将setInterval()提供的轮询Javascript函数的计时器ID存储在全局变量中,并在页面调用onUnload()时停用计时器以停用轮询。

答案 1 :(得分:2)

如果没有通知,getNotifications会返回什么? jQuery期望返回一个JSON格式,但是当你只回显空字符串时,请求失败,因为响应的格式不是JSON。确保每次都回显JSON字符串。

答案 2 :(得分:2)

这个怎么样?我假设$。(get)在一个名为notificationPoll()的函数中;一旦完成就重新调用。

$.ajax({
    url: event_feed_href,
    async: false,
    timeout: 60000,
    done: function(data) {
            var got_json=false;
            try {
                var json = JSON.parse(data);
                got_json=true;
            }
            catch(e) {
                // failed to return JSON data
                alert('Wierd!');
            } 
            if(got_json) {
                // process json data
                alert('New Notification!');
            }
        },
    always: function() {
            notificationPoll();
        }
    });

我已经完成了并且总是在这里,因为jQuery说贬值成功:失败:

答案 3 :(得分:1)

我对代码中止感兴趣,可能有你的答案。它可能由于多种原因而发生

  • Query.get失败。 Ajax调用因任何原因都不起作用。解析错误。
  • 错误的javascript语法。例如:成功处理程序中的代码期望输入参数中的events属性可能不是真的。

对于jQuery.get,正如jQuery.get(https://api.jquery.com/jQuery.get/)文档中所建议的,该函数可以默默地失败,我建议使用.ajaxError来查看get是否失败。

  

如果使用jQuery.get()的请求返回错误代码,除非脚本还调用了全局.ajaxError()方法,否则它将无提示失败。或者,从jQuery 1.5开始,jQuery.get()返回的jqXHR对象的.error()方法也可用于错误处理。

对于javascript语法错误,我建议逐步执行firebug调试器。在成功处理程序的第一行添加断点,然后从那里逐步执行每一行。这很乏味,但它确实有效。