Улучшение производительности Ajax при длинном опросе - PullRequest
5 голосов
/ 19 января 2010

Я пишу веб-приложение ( только для Firefox ), в котором используется длинный опрос (с помощью возможностей jQuery ajax) для отправки более или менее постоянных обновлений с сервера на клиент. Я обеспокоен последствиями того, что работа будет продолжительной в течение длительного периода времени, скажем, весь день или всю ночь. Базовый код скелета таков:

function processResults(xml)
{
    // do stuff with the xml from the server
}

function fetch()
{
    setTimeout(function ()
    {
        $.ajax({
            type: 'GET',
            url: 'foo/bar/baz',
            dataType: 'xml',
            success: function (xml)
            {
                processResults(xml);
                fetch();
            },
            error: function (xhr, type, exception)
            {
                if (xhr.status === 0)
                {
                console.log('XMLHttpRequest cancelled');
                }
                else
                {
                    console.debug(xhr);
                    fetch();
                }
            }
        });
    }, 500);
}

(Полсекунда "спит" так, что клиент не забивает сервер, если обновления возвращаются клиенту быстро - как обычно.)

После того, как вы оставили его включенным на ночь, он начинает ползти Firefox. Я думал, что это может быть частично вызвано большой глубиной стека, так как я в основном написал бесконечно рекурсивную функцию. Однако, если я использую Firebug и выбрасываю точку останова в fetch, похоже, что это не так. Стек, который показывает мне Firebug, имеет глубину всего 4 или 5 кадров, даже через час.

Одним из решений, которое я рассматриваю, является изменение моей рекурсивной функции на итеративную, но я не могу понять, как бы я вставил задержку между запросами Ajax без вращения . Я посмотрел на ключевое слово JS 1.7 "yield" , но не могу обернуть его, чтобы понять, нужно ли мне это здесь.

Лучшее решение - просто периодически обновлять страницу, скажем, раз в час? Существует ли более качественный шаблон с длинным опросом, который не навредит браузеру даже после 8 или 12 часов работы? Или я должен просто вообще пропустить длинный опрос и использовать другой шаблон «постоянного обновления», поскольку я обычно знаю, как часто сервер будет получать ответ для меня?

Ответы [ 4 ]

2 голосов
/ 01 апреля 2010

Также возможно, что это FireBug.Вы - консоль. Журналы, что означает, что вы, вероятно, открыли вкладку сетевого монитора и т. Д., Что означает, что каждый запрос хранится в памяти.

Попробуйте отключить его, посмотрите, поможет ли это.

2 голосов
/ 19 января 2010

Я подозреваю, что память просачивается от processResults().

Я использовал код, очень похожий на ваш, в веб-приложении с длительным опросом, которое может работать непрерывно в течение нескольких недель без обновления страницы.

Ваш стек не должен быть глубоким, потому что fetch() возвращается немедленно. У вас нет бесконечно рекурсивного цикла.

Возможно, вы захотите использовать Firefox Leak Monitor Add-on , чтобы помочь вам найти утечки памяти.

1 голос
/ 14 мая 2014

Это плохая идея вызывать fetch() изнутри самого метода. Рекурсивность лучше использовать, когда вы ожидаете, что в какой-то момент метод достигнет конца и результаты начнут отправляться вызывающей стороне. Дело в том, что когда вы вызываете метод рекурсивно, он сохраняет метод вызывающей стороны открытым и использует память. Если у вас всего 3-4 кадра, это потому, что jQuery или браузер как-то «исправляют» то, что вы сделали.

Последние версии jquery по умолчанию поддерживают длинные опросы. Таким образом, вы можете быть уверены, что вы не зависите от интеллекта браузера, чтобы справиться с вашим бесконечным рекурсивным вызовом. При вызове метода $.ajax() вы можете использовать приведенный ниже код, чтобы провести длинный опрос в сочетании с безопасным ожиданием в 500 миллисекунд перед новым вызовом.

function myLongPoll(){
    setTimeout(function(){
        $.ajax({
            type:'POST',
            dataType: 'JSON',
            url: 'http://my.domain.com/action',
            data: {},
            cache: false,
            success:function(data){

                //do something with the result

            },
            complete: myLongPoll, 
            async : false,
            timeout: 5000
        });
   //Doesn't matter how long it took the ajax call, 1 milisec or 
   //5 seconds (timeout), the next call will only happen after 2 seconds
   }, 2000);

Таким образом, вы можете быть уверены, что вызов $.ajax() закрыт до начала следующего. Это можно доказать, добавив простой console.log() к предыдущему и еще один после вашего $.ajax() вызова.

1 голос
/ 19 января 2010

Глубина стека 4-5 верна.setTimeout и $.ajax - это асинхронные вызовы, которые немедленно возвращаются.Позже обратный вызов вызывается браузером с пустым стеком вызовов.Поскольку вы не можете реализовать длинный опрос синхронно, вы должны использовать этот рекурсивный подход.Невозможно сделать его итеративным.

Я подозреваю, что причина этого замедления в том, что в вашем коде есть утечка памяти.Утечка может быть либо в $.ajax с помощью jQuery (очень маловероятно), либо в вашем processResults вызове.

...