Есть ли что-то вроде памяти или кеша Jquery? - PullRequest
1 голос
/ 21 февраля 2012

Я написал скрипт с jQuery для предварительного просмотра продукта 360deg.Работает просто отлично.Но если я «играю» с ним долгое время (перетаскивание, увеличение, уменьшение и т. Д.), Оно становится все медленнее и медленнее.Если я медленно перетаскиваю мышь, она работает нормально, но она останавливается при быстром перемещении мыши.После перезагрузки страницы она снова работает нормально в течение нескольких минут, а затем замедляется.

Что может вызвать такое поведение?Есть ли что-то вроде памяти jQuery, которая заполняется?

По запросу, некоторые части кода:

Загрузка изображений:

$.getJSON("load.php", {dir: 'images/'}, function(output) {
var imagelist = jQuery.makeArray(output.imagelist);
var zoomlist = jQuery.makeArray(output.zoomlist);
var cache = [];

function preload(arrayOfImages) {
    $(arrayOfImages).each(function(){
        var im = $("<img>").attr("src",this);
        cache.push(im);
        image.attr('src', this);
    });
}
preload(imagelist);

Поворотная часть

holder.mousedown(function(e){
    var enterPosition = e.pageX - this.offsetLeft;
    isDown = true;
    $(document).mousemove(function(e){
        if(isDown && !isZoom){
            var cursorPosition = e.pageX - contOffset.left;
            var xOffset = cursorPosition - enterPosition;
            var step = Math.round(contWidth/countFrames);
            var frameOffset = Math.round(xOffset/step);
            var cycles = Math.abs(Math.floor((frameOffset+startFrame)/countFrames));

            currentFrame = startFrame + frameOffset;
            if(currentFrame >= countFrames){
                currentFrame = currentFrame - countFrames*cycles;
            }       
            if(currentFrame < 0){
                currentFrame = countFrames*cycles + currentFrame;
            }

            image.attr('src', imagelist[currentFrame]);
            $('#info').html(currentFrame);      
            var corner = Math.floor(360/countFrames);                       
            var degrees = corner*currentFrame;                              
            var radians=degrees*Math.PI/180;
            var sine=Math.sin(radians);
            var cose=Math.cos(radians);
            var poinx = rotCenter+rotRadius*sine*-1;
            var poiny = rotCenter+rotRadius*cose
            $('#pointer').css('left',poinx);
            $('#pointer').css('top',poiny);
        };
    });
    $(document).mouseup(function(){
        isDown = false;
        startFrame = currentFrame;
    });
});

Масштабирующая часть

$('#zoom').click(function(e){
    var isZoom = true;

    var offset = holder.offset();
    var startXpos = e.pageX - offset.left;
    var startYpos = e.pageY - offset.top;
    var zoomImg = new Image();

    zoomImg.onload = function() {
        zoomHeight = zoomImg.height;
        zoomWidth = zoomImg.width;

        var leftOverflow = (zoomWidth - contWidth)/-2;
        var topOverflow = (zoomHeight - contHeight)/-2;

        image.attr('src', zoomlist[currentFrame]);
        image.css('left', leftOverflow);
        image.css('top', topOverflow);
        $('#round').fadeOut();
        $('#zoom').fadeOut();           
        holder.addClass('zoomout');
        holder.mousemove(function(e){
            if(isZoom){
                var currentXpos = e.pageX - offset.left;
                var currentYpos = e.pageY - offset.top;

                var xlimit = (zoomWidth-contWidth)*-1;
                var ylimit = (zoomHeight-contHeight)*-1;



                var xSpeedCoeff = Math.floor(zoomWidth/contWidth);
                var ySpeedCoeff = Math.floor(zoomHeight/contHeight);
                var moveLeft = startXpos - currentXpos;
                var moveTop = startYpos - currentYpos;
                var leftOffset = leftOverflow + moveLeft*xSpeedCoeff;
                var topOffset = topOverflow + moveTop*ySpeedCoeff;
                var hMoveLock = false;
                var vMoveLock = false;


                if(leftOffset >= 0){
                    hMoveLock = true;
                    startXpos = startXpos - leftOffset;
                } 
                if(leftOffset <= xlimit){
                    hMoveLock = true;
                    startXpos = startXpos - leftOffset + xlimit;    
                }

                if(topOffset >= 0){
                    vMoveLock = true;
                    startYpos = startYpos - topOffset;
                } 
                if(topOffset <= ylimit){
                    vMoveLock = true;
                    startYpos = startYpos - topOffset + ylimit; 
                }

                if(!hMoveLock) {
                    image.css('left', leftOffset);
                }
                if(!vMoveLock) {
                    image.css('top', topOffset);
                }

                holder.mousedown(function(){

                    image.attr('src', imagelist[currentFrame]);
                    image.css('left', 0);
                    image.css('top', 0);
                    $('#round').fadeIn();
                    $('#zoom').fadeIn();            
                    holder.removeClass('zoomout');
                    pan = false;
                    isZoom = false;
                });
            }
        });
    }
    zoomImg.src = zoomlist[currentFrame];
}); 

Я знаю, код не понятен, и, как и здесь, сейчас, я был бы благодарен за любой совет.

Ответы [ 3 ]

6 голосов
/ 21 февраля 2012

Существует множество причин, по которым это может произойти, невозможно сказать, не увидев код , смотрите обновление ниже, когда вы разместили код :

Несколько вариантов в моей голове:

  1. Да, вы могли бы выделить много объектов и затем либо не освобождать их, либо мусорсборщик работает медленно.

  2. Вы можете непреднамеренно повторно присоединять обработчики событий снова и снова, и поэтому события (которые в конечном итоге вызывают все подключенные обработчики) замедляются из-за количества(избыточные) обработчики прилагаются.


Обновление после того, как вы опубликовали свой код:

Это # 2, это код, вызывающий сбой (это может быть не только код only ):

holder.mousedown(function(e){
    var enterPosition = e.pageX - this.offsetLeft;
    isDown = true;
    $(document).mousemove(function(e){
        // ...
    });
    $(document).mouseup(function(){
        // ...
    });
});

Когда вы запускаете событие mousedown для элементов holder, вы добавляем новый обработчик для mousemove и mouseup к документу поверх любого объектаndlers, которые уже есть.Таким образом, каждый mousedown вводит новый обработчик в цепочку.Поскольку mousemove происходит с лотом , эта постоянно растущая цепочка обработчиков называется лотом .

Вы должны либо только присоединять mousemove и mouseup обработчики один раз , а не на каждый mousedown, или вы должны быть уверены, что удалите их на mouseup.(Последнее потребует, чтобы вы не использовали анонимные функции, как в настоящее время, потому что вам нужно передать такую ​​же ссылку на функцию в unbind, которую вы [косвенно] передали в bind. Редактировать : Или вы можете использовать материал событий jQuery "namespaced".)


FWIW, это должно помочь вам начать работу с возможностью подключения сразу:

(function() {   // Scoping function so isDown and enterPosition aren't globals
    var isDown = false,
        enterPosition;

    // I don't know where `holder` or `startFrame` come from, but presumably you do

    // Hook up mousedown on holder
    holder.mousedown(function(e){
        enterPosition = e.pageX - this.offsetLeft;
        isDown = true;
    });

    // Hook up mousemove on document (just once)
    $(document).mousemove(function(e){
        // Flag controls whether we do anything
        if(isDown && !isZoom){
            var cursorPosition = e.pageX - contOffset.left;
            var xOffset = cursorPosition - enterPosition;
            var step = Math.round(contWidth/countFrames);
            var frameOffset = Math.round(xOffset/step);
            var cycles = Math.abs(Math.floor((frameOffset+startFrame)/countFrames));

            currentFrame = startFrame + frameOffset;
            if(currentFrame >= countFrames){
                currentFrame = currentFrame - countFrames*cycles;
            }       
            if(currentFrame < 0){
                currentFrame = countFrames*cycles + currentFrame;
            }

            image.attr('src', imagelist[currentFrame]);
            $('#info').html(currentFrame);      
            var corner = Math.floor(360/countFrames);                       
            var degrees = corner*currentFrame;                              
            var radians=degrees*Math.PI/180;
            var sine=Math.sin(radians);
            var cose=Math.cos(radians);
            var poinx = rotCenter+rotRadius*sine*-1;
            var poiny = rotCenter+rotRadius*cose
            $('#pointer').css('left',poinx);
            $('#pointer').css('top',poiny);
        };
    });

    // Hook mouseup on document (just once)
    $(document).mouseup(function(){
        isDown = false;
        startFrame = currentFrame;
    });
})();

Если ваш код уже находится в области видимости, вам не нужен новый, который я представил.

1 голос
/ 21 февраля 2012

Есть кеш - вы можете получить к нему доступ с помощью $.cache.И, как сказал TJ Crowder, это, скорее всего, причина того, что вы не убираете себя должным образом.

Сделайте Object.keys($.cache).length; в своей консоли, чтобы проверить размер кэша - поиграйте некоторое время и снова проверьте, чтобыподтвердите, что кэш увеличивается, чтобы подтвердить утечки на основе jquery

, и вы вызываете утечку, поскольку mouseup не отменяет привязку событий mouseup и mmousemove

$(document).mouseup(function(){
    $(document).unbind('mouseup').unbind('mousemove');
    isDown = false;
    startFrame = currentFrame;
});

, это должно сильно помочь

Проблема заключалась в том, что в основном каждый раз, когда вы нажимали мышь, вы снова и снова связывали mousemove и mouseup, поэтому после нескольких нажатий все вычисления умножались на количество нажатий мыши.Вы также можете использовать пространство имен для событий mousemove и mouseup для отмены привязки по пространству имен, а не по двум событиям по отдельности.

Кэшированные переменные также могут немного помочь - особенно при таких тяжелых операциях - mousemove запускает много

edit:

для удаления событий с анонимными функциями используйте пространства имен

var doc = $(document);

doc.bind('mousedown', function(e) {

    doc.bind('mousemove.namespace', function(e) { ... });

    doc.bind('mouseup.namespace', function(e) {

        doc.unbind('.namespace');

        // do whatever else you need to do on mouseup
    });
});

просто измените пространство имен на то, что вам больше подходит!Обратитесь к документации jQuery для получения дополнительной информации о событиях в пространстве имен http://docs.jquery.com/Namespaced_Events

, кроме того, если вы не передадите какую-либо функцию типу события, который хотите отменить, он отменит все события данного типа независимо от его пространства именили если он был назван функцией или анонимным

0 голосов
/ 25 февраля 2012

Итак, проблема была вызвана функцией масштабирования.Что я сделал, чтобы решить эту проблему:

Я переместил эту часть

holder.mousedown(function(){
   image.attr('src', imagelist[currentFrame]);
   image.css('left', 0);
   image.css('top', 0);
   $('#round').fadeIn();
   $('#zoom').fadeIn();            
   holder.removeClass('zoomout');
   pan = false;
   isZoom = false;
});

за пределы

holder.mousemove(function(e){
   if(isZoom){

Я использовал пространства имен для отмены привязки событий мыши.

holder.on('mousemove.dragpan', (function(e){
}));

holder.mousedown(function(){
   holder.off('mousemove.dragpan');
});

Спасибо еще раз за все чаевые!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...