javascript - 长轮询 : Why do some messages come in twice?

标签 javascript php ajax chat long-polling

我目前正在构建一个带有日志轮询的聊天应用程序。 原型(prototype)位于此处:http://chat.alexanderjank.de

在服务器端使用 PHP。但我认为这是一个 javascript 问题,一些消息出现了几次。

使用的 javascript 代码是:

var t;
var xhr;
var ids = [];
var panel = $('#posts-panel');

var indexOf = function(needle) {
    if(typeof Array.prototype.indexOf === 'function') {
        indexOf = Array.prototype.indexOf;
    } else {
        indexOf = function(needle) {
            var i = -1, index = -1;

            for(i = 0; i < this.length; i++) {
                if(this[i] === needle) {
                    index = i;
                    break;
                }
            }

            return index;
        };
    }

    return indexOf.call(this, needle);
};

function getNewPosts(timestamp) {
  xhr = $.ajax({
    url: 'chat.php',
    data: 'timestamp=' + timestamp,
    dataType: 'JSON',
})
  .done(function(data) {
    clearInterval( t );
    // If there was results or no results
    // In both cases we start another AJAX request for long polling after 1 second
    if (data.message_content == 'results' || data.message_content == 'no-results') {
        t = setTimeout(function() { getNewPosts(data.timestamp); }, 1000);
        // If there was results we will append it to the post div
        if (data.message_content ==  'results') {
            // Loop through each post and output it to the screen
            $.each(data.posts, function(index, val) {
               if(indexOf.call(ids, val.msg_id) == '-1') {
                    ids.push(val.msg_id);
                    $('<li class="media"><div class="media-body"><div class="media"><a class="pull-left" href="#"><img class="media-object img-circle " src="assets/img/user.png" /></a><div class="media-body" >'+val.message_body+'<br /><small class="text-muted">Alex Deo | '+ val.posted_time +'</small><hr /></div></div></div></li>').appendTo('.posts');
                    panel.scrollTop(panel[0].scrollHeight);
                }
            });
        }
    }
});
}

$(document).ready(function(){

    $(function() {
        $('#posts-panel').jScrollPane({
        horizontalGutter:5,
        verticalGutter:5,
        'showArrows': false
        });
    });

    $('.jspDrag').hide();
    $('.jspScrollable').mouseenter(function(){
        $(this).find('.jspDrag').stop(true, true).fadeIn('slow');
    });
    $('.jspScrollable').mouseleave(function(){
        $(this).find('.jspDrag').stop(true, true).fadeOut('slow');
    });


    if (!Date.now) {
        Date.now = function() { return new Date().getTime(); };
    }

    panel.scrollTop(panel[0].scrollHeight);

    // Create an AJAX request to the server for the first time to get the posts
    $.ajax({
        async: false,
        url: 'chat.php?full_page_reload=1',
        type: 'GET',
        dataType: 'JSON',
    })
    .done(function(data) {
        // Assign the this variable to the server timestamp
        // that was given by the PHP script
        serverTimestamp = data.timestamp;
        if(data.posts != 'nothing') {
             $.each(data.posts, function(index, val) {
                    ids.push(val.msg_id);
                    $('<li class="media"><div class="media-body"><div class="media"><a class="pull-left" href="#"><img class="media-object img-circle " src="assets/img/user.png" /></a><div class="media-body" >'+val.message_body+'<br /><small class="text-muted">Alex Deo | '+ val.posted_time +'</small><hr /></div></div></div></li>').appendTo('.posts');
                    panel.scrollTop(panel[0].scrollHeight);
            });
        }
    })
    .fail(function() {
        alert('There was an error!');
    });
    // When the form is submitted
    $('#sendMessage').on('submit', function(event) {
        // xhr.abort();
        $.ajax({
            url: 'chat.php?post=1',
            type: 'POST',
            dataType: 'JSON',
            data: $('#sendMessage').serialize()
        })
        .done(function(data) {
            // Reset the form values
            $('#sendMessage')[0].reset();
        })
        .fail(function() {
            // When there was an error
            alert('An error occured');
        });
        // Prevent the default action
        event.preventDefault();
    });
    // Start the actual long polling when DOM is ready
    getNewPosts(serverTimestamp);
});

请帮我解决这个问题。

最佳答案

确保一条消息不会出现两次的一种方法是在您已有的循环函数中使用 ID 检查该消息在 DOM 中是否存在:

$.each(data.posts, function(index, val) {
    if(!$('#message-'+val.id).length) {
        // Add message to the DOM
    }
});

如果消息已经在 DOM 中,则不会再次添加。我看到您在回复中已经有一个 ID,所以可以非常直接地进行操作。

关于javascript - 长轮询 : Why do some messages come in twice?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26697744/

相关文章:

Javascript素数函数控制台问题

javascript - SharePoint 工作流订阅服务失败

php - 将依赖注入(inject)容器传递给静态方法

javascript - 如何获取对象的第一个键?

javascript - 在具有随机起始索引的数组中选择 4 个值

php - Laravel 根据身份验证状态显示页面

php - Laravel 数据表排序问题

javascript - 我如何将下拉值传递给ajax Controller ?

javascript - 使用 Javascript Ajax 调用的 Azure 机器学习

javascript - 下拉列表和 Selenium with Python