2009-12-18 33 views
25

Tôi sử dụng tải tập lệnh động để giảm thời lượng tải trang ban đầu. Để đảm bảo rằng các hàm và đối tượng được xác định bởi một tập lệnh có thể truy cập được, tôi cần đảm bảo rằng tập lệnh đã được tải đầy đủ.Script.readyState có thể được tin cậy để phát hiện kết thúc tải tập lệnh động không?

Tôi đã phát triển my own Javascript library cho mục đích này và do đó đã thực hiện rất nhiều nghiên cứu về chủ đề này, nghiên cứu cách thực hiện trong các thư viện khác nhau. Trong một cuộc thảo luận liên quan đến vấn đề này, Kyle Simpson, tác giả của LABjs, tuyên bố rằng:

LABjs (và nhiều bộ tải khác) thiết cả "onload" và "onreadystatechange" trên tất cả các yếu tố kịch bản, biết rằng một số trình duyệt sẽ cháy một, và một số sẽ cháy khác ...

Bạn có thể tìm thấy một ví dụ về điều này trong the current version of jQuery as of this writing, v1.3.2:

// Attach handlers for all browsers 
script.onload = script.onreadystatechange = function(){ 
    if (!done && (!this.readyState || 
    this.readyState == "loaded" || this.readyState == "complete")) { 
     done = true; 
     success(); 
     complete(); 

     // Handle memory leak in IE 
     script.onload = script.onreadystatechange = null; 
     head.removeChild(script); 
    } 
}; 

Đó là trạng thái của nghệ thuật, nhưng trong quá trình phân tích một hành vi lạ trong Opera 9.64, tôi đi đến kết luận rằng, bằng cách sử dụng kỹ thuật này, cuộc gọi lại bị bắn quá sớm.

Tôi sẽ đăng các phát hiện của riêng mình để trả lời cho câu hỏi này và muốn thu thập thêm bằng chứng và phản hồi từ cộng đồng.

+0

Bất kỳ ai tìm mã hiện tại trong nhánh 1.x-master jQuery? Có vẻ như họ đã bỏ bằng cách sử dụng '.onreadystatechange' và' .onload' và thay thế chúng bằng lời hứa? [Clicky] (https://github.com/jquery/jquery/blob/1.x-master/src/ajax.js) – Campbeln

Trả lời

7

Trong Opera, thuộc tính script.readyState không thể tin cậy được. Ví dụ, readyState "loaded" có thể được kích hoạt trước khi kịch bản chạy trong Opera 9.64.

Tôi đã biểu diễn the same test trong Opera 9.64 và Opera 10, với kết quả khác nhau.

Trong Opera 9.64, trình xử lý onreadystatechange được kích hoạt hai lần, một lần trước và một lần sau khi tập lệnh chạy. Thuộc tính readyState là "nạp" trong cả hai trường hợp, điều đó có nghĩa rằng giá trị này không thể được tin cậy để phát hiện sự kết thúc của tải kịch bản:

# Fri Dec 18 2009 17:54:43 GMT+0100 
# Opera/9.64 (Windows NT 5.1; U; en) Presto/2.1.1 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
readystatechange: loaded 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 
readystatechange: loaded 

Trong Opera 10, xử lý onreadystatechange vẫn bị sa thải hai lần với các giá trị " được tải ", nhưng cả hai lần sau khi tập lệnh chạy:

# Fri Dec 18 2009 18:09:58 GMT+0100 
# Opera/9.80 (Windows NT 5.1; U; en) Presto/2.2.15 Version/10.10 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 
readystatechange: loaded 
readystatechange: loaded 

Các hành vi khác nhau này cho thấy rằng onreadystatechange không phải là cách đáng tin cậy để phát hiện kết thúc tải tập lệnh trong Opera. Vì Opera cũng hỗ trợ trình nghe onload, nên nên sử dụng cơ chế khác này thay thế.

Dựa trên kết quả của các thử nghiệm này, onreadystatechange chỉ nên được sử dụng để phát hiện kết thúc tải tập lệnh trong Internet Explorer và không nên được đặt trong các trình duyệt khác.

+0

Ít nhất, bạn có thể bỏ qua sự kiện đầu tiên. –

+2

@Justin Johnson có vẻ khó xử, bạn sẽ đếm các sự kiện "đã tải", nhưng chỉ trong Opera? –

3

Trong Firefox, Safari và Chrome, trình xử lý onreadystatechange không bao giờ được gọi.

Tôi tạo ra một trường hợp thử nghiệm ngắn, tạo ra một kịch bản năng động chỉ với bộ xử lý onreadystatechange:

<script type="text/javascript" language="javascript"> 
bezen.log.info(new Date(),true); 
bezen.log.info(navigator.userAgent,true); 

// Activate logs 
bezen.log.on(); 
bezen.log.info('Test for script.readyState behavior started'); 

var script = document.createElement('script'); 
script.src = 'test1.js'; 
script.onreadystatechange = function(){ 
    bezen.log.info('readystatechange: '+script.readyState); 
}; 
document.body.appendChild(script); 
bezen.log.info('Added script with onreadystatechange handler'); 
</script> 

tôi thực hiện các bài kiểm tra trên một tập tin địa phương trong Firefox 2, Firefox 3, Firefox 3.5, Safari 3, Safari 4 và Chrome 3 và có kết quả tương tự (tại đây các nhật ký được ghi lại trong FF 3.5):

Fri Dec 18 2009 17:53:58 GMT+0100 
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 

Onreadystatechange không bao giờ được gọi. Trong các trình duyệt này, chỉ có trình nghe onload rất hữu ích để phát hiện kết thúc quá trình tải tập lệnh, thì không cần đến onreadystatechange.

1

Trong Internet Explorer, trình xử lý onreadystatechange kích hoạt như mong đợi, sau khi kết thúc tập lệnh.

tôi thực hiện các same test trong Internet Explorer 6, Internet Explorer 7 và Internet Explorer 8, với kết quả tương tự trong ba trình duyệt (ở đây các bản ghi ghi trong Internet Explorer 6):

Fri Dec 18 18:14:51 UTC+0100 2009 
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 
readystatechange: complete 

Ở đây, với một thử nghiệm bằng cách sử dụng một tập tin địa phương, readyState luôn luôn là "hoàn thành", và nó vẫn giống nhau sau khi làm mới một số trang.

Tuy nhiên, như đã nêu trong this post by Nicholas C. Zakas, bạn cũng có thể quan sát "đã tải" và "hoàn thành" hoặc chỉ "được tải" trong các trường hợp khác nhau.

1

Tôi đã tìm thấy trình khám phá internet (thử nghiệm trong 9) KHÔNG CẦN LUÔN sẵn sàng cho tập lệnh của bạn khi readyState === 'tải'. Tôi đã thành công khi sử dụng trình xử lý sự kiện này (trong 9 điều kiện) hủy kích hoạt. Đã được kéo tóc của tôi ra trước.

0

Kết quả tương tự trong Chrome.

Không sử dụng được ...

Chỉ tải và onerror.

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