我有一个简单的函数,导致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>元素附加到具有更高分辨率版本的图像的'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事件仅发生一次。尽管由于该元素是在之后直接删除的,所以我不明白为什么这会有所不同。

我真的很想知道是否有人可以对此进行阐述,以便我将来可以避免此类问题。干杯。

最佳答案

如果您没有$(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即可满足您的目的。

07-24 09:44
查看更多