Javascript 是否有类似Jquery内存或缓存的东西?

Javascript 是否有类似Jquery内存或缓存的东西?,javascript,jquery,caching,memory,Javascript,Jquery,Caching,Memory,我已经用jQuery为360deg产品预览编写了一个脚本。它很好用。但是如果我玩了很长时间,拖动、放大、缩小等等,它会变得越来越慢。如果我慢慢拖动鼠标,它可以正常工作,但在快速鼠标移动时会冻结。重新加载页面后,它会再次正常工作几分钟,然后变慢 什么会导致这种行为?有没有像jQuery这样的内存变满了 根据请求,代码的某些部分: 正在加载图像: $.getJSON("load.php", {dir: 'images/'}, function(output) { var imagelist = jQ

我已经用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];
}); 

我知道,代码不清楚,现在就在这里,我非常感谢您的建议。

可能发生这种情况的原因很多,如果没有看到代码,就不可能说,请参阅下面的更新,因为您已经发布了代码:

我脑海中浮现出几个可能性:

是的,您可能分配了很多对象,然后没有释放它们,或者垃圾收集器速度慢

您可能会无意中一次又一次地重新附加事件处理程序,因此最终触发所有附加处理程序的事件会因为附加的冗余处理程序的数量而减慢速度

发布代码后更新:

它是2,这是有问题的代码可能不是唯一有问题的代码:

holder.mousedown(function(e){
    var enterPosition = e.pageX - this.offsetLeft;
    isDown = true;
    $(document).mousemove(function(e){
        // ...
    });
    $(document).mouseup(function(){
        // ...
    });
});
当mousedown事件在holder元素上激发时,您将在已有的处理程序之上为mousemove和mouseup添加一个新的处理程序。因此,每个mousedown都会向链引入一个新的处理程序。由于mousemove经常发生,因此不断增加的处理程序链会被调用很多次

您应该只附加mousemove和mouseup处理程序一次,而不是在每次mousedown上,或者您应该确保在mouseup上删除它们。后者将要求您不要像当前那样使用匿名函数,因为您需要将相同的函数引用传递到unbind,而您[间接]传递到bind。编辑:也可以使用jQuery的命名空间事件

FWIW,这应该可以让您开始使用attach it once版本:

(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;
    });
})();

如果您的代码已经在作用域函数中,您就不需要我介绍的新代码。

出现这种情况的原因有很多,如果没有看到代码,就不可能说,请参阅下面的更新,因为您已经发布了代码:

我脑海中浮现出几个可能性:

是的,您可能分配了很多对象,然后没有释放它们,或者垃圾收集器速度慢

您可能会无意中一次又一次地重新附加事件处理程序,因此最终触发所有附加处理程序的事件会因为附加的冗余处理程序的数量而减慢速度

发布代码后更新:

它是2,这是有问题的代码可能不是唯一有问题的代码:

holder.mousedown(function(e){
    var enterPosition = e.pageX - this.offsetLeft;
    isDown = true;
    $(document).mousemove(function(e){
        // ...
    });
    $(document).mouseup(function(){
        // ...
    });
});
当mousedown事件在holder元素上激发时,您将在已有的处理程序之上为mousemove和mouseup添加一个新的处理程序。因此,每个mousedown都会向链引入一个新的处理程序。由于mousemove经常发生,因此不断增加的处理程序链会被调用很多次

您应该只附加mousemove和mouseup处理程序一次,而不是在每次mousedown上,或者您应该确保在mouseup上删除它们。后者将要求您不要像当前那样使用匿名函数,因为您需要将相同的函数引用传递到unbind,而您[间接]传递到bind。编辑:也可以使用jQuery的命名空间事件

FWIW,这应该可以让您开始使用attach it once版本:

(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;
    });
})();

如果您的代码已经在作用域函数中,则不需要我介绍的新代码。

有一个缓存-您可以使用$.cache访问它。正如T.J.克劳德所说,这很可能是你没有正确清理自己的原因

执行一个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会触发很多

编辑:

要使用匿名函数删除事件,请使用名称空间

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文档以了解有关命名空间ev的更多信息 恩茨


除此之外,如果您不将任何函数传递给要解除绑定的事件类型,则它将解除绑定给定类型的所有事件,而不管其名称空间是什么,或者它是否命名为function或anonymous one

有一个缓存-您可以使用$.cache访问它。正如T.J.克劳德所说,这很可能是你没有正确清理自己的原因

执行一个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会触发很多

编辑:

要使用匿名函数删除事件,请使用名称空间

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文档以了解有关命名空间事件的更多信息


除此之外,如果您不将任何函数传递给要解除绑定的事件类型,它将解除绑定给定类型的所有事件,而不管其名称空间是什么,或者它是名为function还是匿名的

因此,问题是由缩放函数引起的。我是如何解决的:

我已经移动了这个部分

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');
});

再次感谢所有的Tipp

因此,问题是由缩放功能引起的。我是如何解决的:

我已经移动了这个部分

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');
});


再次感谢所有的Tipp

好的,实际上我想把代码放到JSFIDLE上,但是它通过JSON请求加载图像,php=>在JSFIDLE上不起作用……我已经根据发布的代码更新了我的答案。所以,我解决了这个问题。我必须移动holder.mousedown函数{在holder.on'mousemove.dragpan'上,函数e之外{在缩放功能中。我还使用名称空间来解除事件绑定。谢谢你们的提示,这非常有用!@Sobakinet:如果下面的答案都不可接受,但你已经解决了问题,请将解决方案作为答案发布,然后当系统允许你接受它时。@T.J.Crowder这两个答案确实有助于解决问题。我认为我没有道德权利接受我的解决方案,这完全是基于你的提示和建议。我对StackOverflow不太熟悉-我真的需要接受其中一个答案吗?另一个问题,导致问题的代码部分被编辑从我的问题帖子中删除了…好吧,实际上我想把代码放在上面jsfiddle,但它通过JSON请求加载图像,php=>它在jsfiddle上不起作用…我根据发布的代码更新了我的答案。因此,我解决了这个问题。我必须将holder.mousedownfunction{移到holder.on'mousemove.dragpan'上的holder.mousedownfunction{外部{在缩放功能中。我还使用名称空间来解除事件绑定。谢谢你们的提示,这非常有用!@Sobakinet:如果下面的答案都不可接受,但你已经解决了问题,请将解决方案作为答案发布,然后当系统允许你接受它时。@T.J.Crowder这两个答案确实有助于解决问题。我认为我没有道德权利接受我的解决方案,这完全是基于你的提示和建议。我对StackOverflow不太熟悉-我真的需要接受其中一个答案吗?另一个问题是,导致问题的代码部分被编辑从我的问题帖子中删除了…快告诉我吧。是的,这是我的猜测还有…没有示例代码。:好的,我现在试着理解它。问题是页面上有一个holder元素。如果用户单击它然后拖动鼠标,动画必须开始。但是如果用户将鼠标拖动到holder元素外,动画必须仍然运行。这就是为什么我在holder.mousedown内有$document.mousemove。所以我必须解除绑定document.mouseup事件上的holder.musedown函数将尝试计算它out@Sobakinet:您不一定要解除绑定,另一种选择是绑定一次并使用您已有的标志。请参阅我的更新以了解如何工作。嗯……似乎没有多大帮助。您能看一下吗?听到问题似乎开始了吗ter放大和缩小。@Sobakinet:对不起,现在不能这样做。我看了一下,有点离题,但如果你使用一致、清晰的代码缩进,它会对你和任何可能需要阅读代码的人有很大帮助。问题中的代码缩进,以及链接中的代码缩进,到处都是。很难阅读是的,那就是我

我想也是。。。无示例代码:好的,我现在试着理解它。问题是页面上有一个holder元素。如果用户单击它,然后拖动鼠标,动画必须开始。但是,如果用户将鼠标拖动到holder元素之外,它仍然必须运行。这就是为什么我有$document.mousemoveinholder.mousedown。所以我必须解除document.mouseup事件上holder.musedown函数的绑定。。。我会设法解决的out@Sobakinet:您不必解除绑定,另一种选择是绑定一次并使用您已有的标志。请看我的更新,了解如何工作。嗯。。。这似乎没有多大帮助。你能看一下吗?在放大和缩小之后,问题似乎开始了。@Sobakinet:对不起,现在不能这样做。我快速浏览了一下,有点离题了,但如果您使用一致、清晰的代码缩进,它会对您以及可能需要阅读您的代码的任何人有很大帮助。问题和链接中的代码缩进到处都是。很难读。谢谢你的回答。T.J.Crowder在上面写道,它将不适用于匿名函数。但是您的解决方案仍然有匿名函数?请查看对我答案的编辑-我添加了底部带有名称空间的解决方案,它可以完美地与匿名函数配合使用fine@Sobakinet:Tom说得很对,如果使用名称空间,则可以解除绑定处理程序,而无需引用最初绑定的实际函数。这是一个我一直忘记的非常有用的技巧-再来一次,我也要试试。你可以看看我在T.J.Crowder的一篇帖子的评论中发布的例子,如果你想做一个好的演示:试着按照我在编辑中告诉你的方式来做,它会工作得很好-你看到的问题是因为没有解开mousemove+mouseupThx的答案。T.J.Crowder在上面写道,它将不适用于匿名函数。但是您的解决方案仍然有匿名函数?请查看对我答案的编辑-我添加了底部带有名称空间的解决方案,它可以完美地与匿名函数配合使用fine@Sobakinet:Tom说得很对,如果使用名称空间,则可以解除绑定处理程序,而无需引用最初绑定的实际函数。这是一个我一直忘记的非常有用的技巧-再来一次,我也要试试。你可以看看我在T.J.Crowder的一篇帖子的评论中发布的例子,如果你想做一个好的演示:试着按照我在编辑中告诉你的方式去做,它会工作得很好-你看到的问题是因为没有绑定mousemove+mouseup