为什么我的jQuery函数在IE 8中导致“Stack Overflow”错误?

时间:2012-05-17 02:08:21

标签: javascript jquery

我有一个简单的函数,它会在IE 8中导致堆栈溢出错误。虽然我没有测试IE 7或6,但是在任何其他浏览器中似乎都没有出现这个问题。

确切的错误如下: -

 SCRIPT28: Out of stack space 
 jquery.min.js, line 2 character 7498
 SCRIPT2343: Stack overflow at line: 2 

有问题的功能:

function switchImage(size, objid, prefix, fullimage){

    if(size !== 'full'){
        var image = prefix + size + '/' + size +'_' + fullimage;
    }
    else {
        var image = prefix + size + '/' + fullimage;
    }

    $('#' + objid).data('type', size)
        .append('<img id="preload" src="' + image + '" style="display:none;" />')
            .find('#preload').load(function(){
                $('#' + objid).find('img').attr('src', image);
                $(this).remove();
            });
}

为了概述用例,我将解释这个功能的用途:

当用户调整图像大小时(使用jqueryUI调整大小),将在另一个函数中比较宽度/高度。

一旦图像增长到一定大小,然后调用此函数,如您所见,将隐藏的<img>元素附加到DOM,并使用更高分辨率版本的图像的'src'属性(如果用户缩小图像尺寸,则降低。

加载后,可更新可见元素的src属性,并删除隐藏元素。

这证明了图像的优异动态切换,因为用户调整了图像的大小,在整个过程中保持图像质量良好....

我似乎无法解决IE 8中导致问题的原因。删除此功能不会发生错误,虽然存在错误,但功能仍然可以正常工作(尽管调整大小的性能仍然很差)在IE 8)。

非常感谢任何帮助。

更新:我似乎通过将函数重写为以下内容来解决原始问题: -

function switchImage(size, objid, prefix, fullimage){

    var $el = $('#' + objid);

    if(size !== 'full'){
        var image = prefix + size + '/' + size +'_' + fullimage;
    }
    else {
        var image = prefix + size + '/' + fullimage;
    }

    $el.data('type', size);

    $('<img id="preload" src="' + image + '" style="display:none;" />')
        .appendTo($el)
            .one('load', function(){
                $('#' + objid).find('img').attr('src', image);
                    $(this).remove();
                });
}

正如您所看到的,唯一真正的区别是我使用.appendTo()而不是.append()以及使用jQuery .one()方法来确保loa​​d事件只发生一次。虽然之后直接删除了元素,但我不明白为什么这会产生任何影响。

我真的很想知道是否有人可以对此有所了解,以便我可以学习如何在将来避免这些问题。欢呼声。

1 个答案:

答案 0 :(得分:3)

如果您没有$(this).remove(),那么您的初始函数将直接进入无限循环。基本上您正在做的是将src属性设置为所有 img标记,包括预加载图像本身。 (将$(this).remove()替换为console.log('loaded')并观察它在Firebug中无限循环播放)

我猜想在IE8中,一旦属性设置为预加载图像,它会先执行事件处理程序,然后执行下一行$(this).remove() (解释堆栈溢出),而其他浏览器可能首先完成了整个函数的执行,从而删除了预加载图像,这阻止了无限循环。 (这只是猜测)

初始版本的猴子补丁将使用.find('img:not(#preload)')而不是.find('img')

您的补丁也会阻止无限循环,因为.one()确保它只运行一次。

但最终我会将该函数重构为以下内容:

function switchImage(size, objid, prefix, fullimage){

    var $el = $('#' + objid),
        $image = $el.find('img'),
        $preload = $('<img>');

    if(size !== 'full'){
        var image = prefix + size + '/' + size +'_' + fullimage;
    }
    else {
        var image = prefix + size + '/' + fullimage;
    }

    $el.data('type', size);

    $preload
        .on('load', function () {
            $image.attr('src', image);
        })
        .attr('src', image);
}

另请注意,预加载图像实际上不需要显式附加到DOM以满足您的目的。