2012-05-17 33 views
6

Tôi có một chức năng đơn giản gây ra lỗi tràn ngăn xếp trong IE 8. Vấn đề không xuất hiện trong bất kỳ trình duyệt nào khác mặc dù tôi chưa thử nghiệm IE 7 hoặc 6.Tại sao hàm jQuery của tôi lại gây ra lỗi 'Stack Overflow' trong IE 8?

Lỗi chính xác như sau: -

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

các chức năng trong câu hỏi:

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

Để đưa ra một tổng quan về các trường hợp sử dụng tôi sẽ giải thích mục đích của chức năng này:

Khi người dùng thay đổi kích thước hình ảnh (sử dụng thay đổi kích thước jqueryUI) chiều rộng/chiều cao được so sánh trong một hàm khác.

Khi hình ảnh có kích thước nhất định, chức năng này sau đó được gọi như bạn có thể thấy, gắn một phần tử ẩn <img> vào DOM với thuộc tính 'src' của phiên bản có độ phân giải cao hơn (hoặc thấp hơn) nếu hình ảnh đã được cắt giảm bởi người sử dụng.

Một khi nó đã được nạp thuộc tính src của phần tử có thể nhìn thấy được cập nhật và các yếu tố ẩn được lấy ra.

này chứng tỏ chuyển động tuyệt vời của hình ảnh như thay đổi kích thước sử dụng chúng giữ chất lượng hình ảnh tốt trong suốt quá trình ....

Tôi dường như không thể tìm ra nguyên nhân gây ra sự cố trong IE 8. Với chức năng này, không có lỗi xảy ra, và mặc dù có lỗi, chức năng vẫn hoạt động như mong muốn (mặc dù hiệu suất thay đổi kích cỡ kém trong IE số 8).

Mọi trợ giúp sẽ được đánh giá cao.

UPDATE: tôi dường như đã giải quyết được vấn đề ban đầu bằng cách viết lại các chức năng như sau: -

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

Như bạn thấy, sự khác biệt duy nhất là tôi đang sử dụng .appendTo() thay vì .append() cũng như sử dụng phương thức jQuery .one() để đảm bảo rằng sự kiện tải chỉ xảy ra một lần. Mặc dù kể từ khi các yếu tố được loại bỏ trực tiếp sau đó tôi không hiểu tại sao điều này sẽ làm cho bất kỳ sự khác biệt.

Tôi thực sự muốn biết liệu có ai có thể làm sáng tỏ điều này để tôi có thể tìm hiểu cách tránh những vấn đề như vậy trong tương lai. Chúc mừng.

+0

Điều gì sẽ xảy ra khi bạn sử dụng phiên bản jQuery không được minfied? Ít nhất theo cách đó bạn sẽ nhận được một tham chiếu có ý nghĩa hơn cho lỗi. – RobG

+0

Điều tương tự cũng xảy ra .... Tin hay không 5 phút sau khi đăng câu hỏi ... Tôi đã giải quyết nó. Nhưng tôi không biết tại sao ... Tôi sẽ cập nhật câu hỏi của mình, vì tôi thực sự muốn hiểu tại sao viết lại nhỏ này lại tạo nên sự khác biệt. – gordyr

+0

@gordyr Bạn có thể cho chúng tôi mã gọi hàm switchImage() để cung cấp cho tôi một số ngữ cảnh không? –

Trả lời

3

Chức năng ban đầu của bạn sẽ chạy thẳng vào vòng lặp vô hạn nếu bạn không có $(this).remove(). Về cơ bản những gì bạn đang làm là đặt thuộc tính src thành tất cả các thẻimg, bao gồm cả hình ảnh tải trước. (Thay thế $(this).remove() với console.log('loaded') và xem nó vòng lặp vô hạn trong Firebug)

Tôi đoán rằng trong IE8, một khi thuộc tính được thiết lập để hình ảnh tải trước là tốt, nó gọi 'tải' xử lý sự kiện của bạn đầu tiên trước thực hiện các dòng tiếp theo là $(this).remove() (giải thích tràn ngăn xếp), trong khi các trình duyệt khác có thể đã hoàn thành trước tiên thực hiện toàn bộ hàm trước, do đó xóa hình ảnh tải trước, ngăn chặn vòng lặp vô hạn.(Đây chỉ là phỏng đoán)

Bản vá khỉ cho phiên bản ban đầu sẽ là sử dụng .find('img:not(#preload)') thay vì chỉ .find('img').

Bản vá của bạn cũng ngăn vòng lặp vô hạn vì .one() đảm bảo nó chỉ chạy một lần.

Nhưng cuối cùng tôi sẽ cấu trúc lại các chức năng như sau:

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

Cũng lưu ý rằng các hình ảnh tải trước thực sự không cần phải được nối một cách rõ ràng để DOM để phục vụ mục đích của bạn.

Các vấn đề liên quan