2010-05-10 27 views
6

Tôi đang thêm một số thẻ <script> động vào phần tử đầu sau khi tải trang. Tôi hiểu rằng các tập lệnh được tải không đồng bộ, nhưng tôi có thể mong đợi chúng được phân tích cú pháp theo thứ tự chúng được thêm vào không?Việc thêm tập lệnh động nên được đặt hàng?

Tôi thấy hoạt động dự kiến ​​trong Firefox, nhưng không phải trong Safari hoặc Chrome. Nhìn vào các tài liệu trong các công cụ nhà phát triển Chrome và Firebug, cả hai hiển thị như sau -

<html> 
    <head> 
    ... 
    <script type="text/javascript" src="A.js"></script> 
    <script type="text/javascript" src="B.js"></script> 
    </head> 
    ... 
</html> 

Tuy nhiên nhìn vào xem tải tài nguyên, chrome dường như để phân tích nào được trả về đầu tiên từ máy chủ, trong khi con đom đóm luôn tải chúng trong thứ tự các thẻ script đã được thêm vào, ngay cả khi B được trả về đầu tiên từ máy chủ.

Tôi có nên mong Chrome/Safari phân tích cú pháp các tệp theo thứ tự được chỉ định không? Sử dụng Chrome 5.0.375.29 beta trên OS X 10.6.3

EDIT (10/5/10): Khi tôi nói phân tích cú pháp, ý tôi là thực hiện - có thể thấy nhiều lợi ích của việc phân tích cú pháp tích cực - thx rikh

EDIT (11/5/10): Ok vì vậy tôi đã cùng nhau thử nghiệm các dòng đó bằng juandopazo bên dưới. Tuy nhiên tôi đã thêm một sự kết hợp của mọi thứ, bao gồm

  1. Thêm phần tử tập lệnh vào phần đầu trực tiếp bằng javascript. (Kiểm tra A -> D)
  2. Thêm phần tử tập lệnh vào đầu bằng cách sử dụng phương thức append() của jquery. (Kiểm tra E -> H)
  3. 'Tải' tập lệnh bằng phương thức getScript() của jquery. (Bài kiểm tra I -> L)

Tôi cũng đã thử tất cả kết hợp thuộc tính 'async' và 'trì hoãn' trên thẻ tập lệnh.

Bạn có thể truy cập vào thử nghiệm tại đây - http://dyn-script-load.appspot.com/ và xem nguồn để xem cách hoạt động. Các kịch bản được nạp đơn giản gọi hàm update(). Điều đầu tiên cần lưu ý, đó là chỉ có các phương pháp thứ nhất và thứ 3 ở trên hoạt động song song - lần thứ hai thực hiện các yêu cầu tuần tự. Bạn có thể thấy một đồ thị này ở đây -

Hình 1 - Biểu đồ Yêu cầu Vòng đời
Request lifecycle Graph http://dyn-script-load.appspot.com/images/dynScriptGraph.png

Nó cũng thú vị mà các append jquery() Phương pháp này cũng khối getScript() gọi - bạn có thể thấy rằng không ai trong số chúng thực hiện cho đến khi tất cả các cuộc gọi append() hoàn tất, và sau đó tất cả chúng chạy song song. Lưu ý cuối cùng về điều này là phương thức append() của jQuery dường như loại bỏ các thẻ script khỏi đầu tài liệu khi chúng đã thực thi. Chỉ có phương pháp đầu tiên để lại các thẻ script trong tài liệu.

Chrome Kết quả

Kết quả là rằng Chrome luôn thực thi kịch bản đầu tiên để trở về, không phụ thuộc vào kiểm tra. Điều này có nghĩa là tất cả các thử nghiệm 'thất bại', ngoại trừ phương thức append jQuery().

Hình ảnh 2 - Chrome 5.0.375.29 beta kết quả
Chrome Results http://dyn-script-load.appspot.com/images/chromeDynScript.png

Firefox Kết quả

Mở firefox, tuy nhiên, có vẻ như nếu phương pháp đầu tiên được sử dụng, và async là sai (tức là không xác định), sau đó kịch bản sẽ đáng tin cậy thực hiện trong gọi món.

Hình 3 - FF 3.6.3 Kết quả
FF Results http://dyn-script-load.appspot.com/images/ffDynScript.png

Lưu ý rằng Safari dường như để cho kết quả khác nhau theo cách tương tự như Chrome, có ý nghĩa.

Ngoài ra, tôi chỉ có độ trễ 500ms đối với tập lệnh chậm, chỉ để giữ cho thời gian bắt đầu- kết thúc giảm. Bạn có thể phải làm mới một vài lần để xem Chrome và Safari thất bại trên mọi thứ. Có vẻ như với tôi rằng không có một phương pháp để làm điều này, chúng tôi không tận dụng khả năng truy xuất dữ liệu song song, và không có lý do tại sao chúng ta không nên (như firefox cho thấy).

+0

Tôi đã nêu lỗi này như một lỗi trong đăng ký vấn đề về chrome - http://code.google.com/p/chromium/issues/detail? id = 46109 – hawkett

Trả lời

2

Xin lỗi vì đã trả lời câu hỏi của riêng tôi, nhưng đã lâu rồi và chúng tôi đã đưa ra giải pháp. Những gì chúng tôi đã đưa ra là để tải javascript đồng thời như văn bản chứa trong một đối tượng json, và sau đó được sử dụng eval() một khi họ đã được tất cả nạp để thực hiện chúng theo thứ tự đúng. Tải đồng thời cộng với thực thi lệnh. Tùy thuộc vào trường hợp sử dụng của bạn, bạn có thể không cần json. Gần đây, dưới đây là một số mã cho thấy những gì chúng tôi đã làm -

// 'requests' is an array of url's to javascript resources 
var loadCounter = requests.length; 
var results = {}; 

for(var i = 0; i < requests.length; i++) { 
    $.getJSON(requests[i], function(result) { 
     results[result.id] = result; 
     ... 
     if(--loadCounter == 0) finish(); 
    }); 
} 

function finish() { 
    // This is not ordered - modify the algorithm to reflect the order you want 
    for(var resultId in results) eval(results[resultId].jsString); 
} 
0

Như tôi đã hiểu, chúng có nghĩa là được thực thi theo thứ tự chúng xuất hiện trong tài liệu. Một số trình duyệt có thể thực hiện một số phân tích cú pháp không đúng thứ tự, nhưng chúng vẫn phải được thực thi theo đúng thứ tự.

+0

Đây cũng là sự hiểu biết của tôi. – hawkett

0

Không, bạn không thể mong đợi rằng tất cả các trình duyệt sẽ hoãn thực thi cả hai tập lệnh cho đến khi cả hai tập lệnh được tải (** đặc biệt khi bạn thêm động).

Nếu bạn muốn thực thi mã trong B.js chỉ sau A.js được nạp sau đó đặt cược tốt nhất của bạn là thêm một callback onload để A.js mà bộ một biến và một số khác để B.js rằng sẽ kiểm tra xem biến mà đã được thiết lập, sau đó nó thực hiện chức năng cần thiết trong B.js nếu nó có (và nếu A.js chưa được tải, nó sẽ bắt đầu hẹn giờ định kỳ kiểm tra cho đến khi nó được tải).

0

Thứ tự tải xuống và thứ tự thực hiện không giống nhau. Trong trang của bạn, ngay cả khi B.js được tải xuống đầu tiên, công cụ của trình duyệt sẽ đợi A.js tiếp tục xử lý trang.

Các tập lệnh được xử lý chắc chắn, không chỉ theo thứ tự chúng xuất hiện trong tài liệu mà còn ở nơi chúng xuất hiện.

Hãy tưởng tượng nếu nó không giống như vậy, sẽ có nhiều lỗi nếu tập lệnh nhỏ của bạn sử dụng jQuery được tải xuống và xử lý trước thư viện jQuery.

Ngoài ra, khi bạn thực hiện "document.write" trong tệp js, nó xuất hiện khi tập lệnh được khai báo. Bạn không thể truy cập các đối tượng DOM đang xuất hiện sau khi khai báo kịch bản. Đây là lý do tại sao có các đề xuất để đặt tập lệnh ở cuối trang, để ngăn quá trình thực thi của họ quá sớm và giảm "thời gian tải nhận được" của trang, bởi vì công cụ hiển thị của trình duyệt bị dừng ngay sau khi tập lệnh được xử lý.

Mike

CHỈNH SỬA: nếu chúng được thêm động với javascript, tôi nghĩ chúng được xử lý theo thứ tự được thêm vào đúng lúc.

+0

Tuyệt vời đây là những gì tôi mong đợi - vì vậy nếu tôi thấy các script * không * được thực hiện theo thứ tự xuất hiện trong tài liệu (cũng là thứ tự mà chúng được thêm vào đúng thời gian), thì đây sẽ là một lỗi trong WebKit? Tôi có bốn điều cho tôi biết điều gì đang xảy ra (1) Cấu trúc thực tế của DOM hiển thị các kịch bản theo thứ tự đúng (2) Khung nhìn tải tài nguyên trong các công cụ dev hiển thị tập lệnh thứ hai được nhận trước (3) Nhật ký giao diện điều khiển hiển thị thứ tự các kịch bản được thêm vào (theo thời gian), và (4) nhật ký bảng điều khiển hiển thị tập lệnh thứ hai được thực thi đầu tiên – hawkett

+0

Có thể ở dòng cuối cùng của A.js, đặt một dòng để bao gồm B.js qua một "document.write"? –

+0

Mục tiêu chính là tải các tập lệnh song song, nhưng thực thi theo thứ tự chúng được thêm vào. Điều này hoạt động trong Firefox, nhưng không hoạt động trong chrome/safari. Tôi có thể sử dụng phương pháp thứ 2 trong bài kiểm tra (xem chỉnh sửa trong bài chính) để đảm bảo trật tự thực hiện đúng trong tất cả các trình duyệt, nhưng nó không đồng thời. Tôi nghĩ rằng thay vì đưa cách tiếp cận được gợi ý của bạn để có được tải nối tiếp (và do đó thực hiện), tôi sẽ đi với jQuery.append(), như không có mã bổ sung là cần thiết trong các kịch bản mình. Điều đó nói rằng, tôi có tải nối tiếp làm việc ngay bây giờ - Tôi đang tìm một giải pháp tải đồng thời để cải thiện hiệu suất - cổ vũ. – hawkett

0

Bạn có thể tải b.js từ a.js để chắc chắn 100% ... mặc dù tôi muốn câu trả lời dứt khoát cho câu hỏi này bản thân mình, đặc biệt là với đồng bộ ajax tải của kịch bản.

+0

Điều đó chắc chắn hoạt động - Tôi đang trong quá trình di chuyển khỏi thực hiện điều đó, để có được lợi ích hiệu suất khi tải các tập lệnh đồng thời :) – hawkett

0

Tôi đã điều tra điều này trong khi làm việc trên một thư viện nhỏ tải mô-đun động như YUI 3. Tôi đã tạo một thử nghiệm nhỏ ở đây tải hai tập lệnh chỉ chèn nội dung vào các div. Một là tệp JS phổ biến và tệp còn lại là tệp PHP đợi 3 giây để thực thi.

http://www.juandopazo.com.ar/tests/asyn-script-test.html

Như bạn có thể thấy, kịch bản được thực thi khi họ kết thúc tải, và không theo thứ tự mà bạn gắn nó vào phần DOM, ở mọi trình duyệt.

+0

Tôi đã xem xét cấu trúc DOM cho thử nghiệm và ghi chú một vài điều - trước hết các kịch bản nằm trong phần thân chứ không phải đầu, và kịch bản thứ hai được liệt kê đầu tiên - vì vậy nếu đặt hàng được vinh danh, bạn sẽ mong đợi tập lệnh 2 thực thi kiểm tra đầu tiên - tốt mặc dù sẽ là tốt để xem kết quả khi các thẻ script theo thứ tự. ta – hawkett

+0

Phải. Xin lỗi, tôi quên đặt chúng vào đầu. Chúng bị sai trật tự bởi vì tôi đã sử dụng insertBefore() thay vì appendChild(). Tôi đã thay đổi nó và kết quả là như nhau. Bạn nên xem xét viết một số loại hàng đợi. Yêu cầu các mô-đun trong các tệp khác nhau gọi các phương thức từ một đối tượng chung. Hãy xem cách YUI3 hoạt động. Các tập lệnh có mã của bạn thường trông giống như: YUI(). Use ('module1', 'module2', function (Y) { // làm điều gì đó }); Và mỗi mô-đun bắt đầu: YUI().thêm ('module1', hàm (Y) { // thêm nội dung của bạn vào Y }); – juandopazo

+0

Cảm ơn vì điều này - Tôi không có đủ uy tín để đánh dấu xin lỗi. Chỉ cần cố gắng tìm ra lý do tại sao tôi thấy firefox hoạt động như mong đợi trong kịch bản của tôi, nhưng không phải trong kịch bản của bạn. Có vẻ như tôi đã hiểu lầm tình hình của mình rồi. – hawkett

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