6

我有一个简单的函数会在 IE 8 中导致 Stack Overflow 错误。尽管我没有测试 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() 方法来确保加载事件只发生一次。虽然由于元素随后被直接删除,但我不明白为什么这会产生任何影响。

我真的很想看看是否有人可以对此有所了解,以便我可以学习如何在将来避免此类问题。干杯。

4

1 回答 1

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 以达到您的目的。

于 2013-04-13T20:51:20.697 回答