Một nguyên tắc khi chúng ta sắp xếp thứ tự các tệp JS [Javascript] thông thường cần phải theo thứ tự nhất định. Trình duyệt sau khi tải mã HTML về sẽ hiển thị các tập lệnh tệp theo thứ tự từ trên xuống. Vì vậy khi nhúng các tệp JS vào ta thường phải đặt chúng theo thứ tự như sau
VD. Đối chiếu với Jquery
Thư viện Jquery=>Các Plugin Jquery=>Script chứa đoạn mã JqueryTheo thứ tự chúng ta đặt đúng giống như đoạn mã sau
Defer Demo ...
Vì vậy, nếu xảy ra sự cố khi đặt tập lệnh. js before file library thì sao?
Kết quả là chúng ta sẽ gặp lỗi trong bảng điều khiển của trình duyệt
tập lệnh. js. 1 Lỗi tham chiếu chưa bắt được. $ không được xác định
tại tập lệnh. js. 1
Cách load file js [Javascript]
Để khắc phục vấn đề này thì trong thẻ tag các bạn thêm thuộc tính defer. Khi sử dụng defer, nó sẽ báo cho trình duyệt là script này chỉ được load khi trang web đã tải và render hoàn thành.
Chú thích.
- Nó chỉ có tác dụng với thẻ tag sử dụng src để nhúng file js, chứ ko làm có tác dụng khi viết trực tiếp code javascript vào trong
- Nó là một thuộc tính boolean và đứng 1 mình
Sau khi thêm defer chúng ta hoàn toàn có thể sử dụng đoạn mã mà không cần phải theo thứ tự thứ 1 nữa
Ngoài ra nếu bạn sử dụng jQuery thì còn 1 cách khác đó là sử dụng đoạn mã jQuery sau để tải tập lệnh. js sau khi trang web render thành công
Hai tệp này sẽ được tải lần thứ tự ở trên, khung tệp được tải trước, sau đó đến tệp ứng dụng
Sau khi 2 tập tin này được tải xong, Render sẽ khởi động tạo ra một Web Worker. Tương tự như Render, Worker cũng cần phải tải 2 tệp
- file worker framework chứa các mã của framework để khởi động kết nối từ Worker tới Render và từ Worker tới Core
- file worker app Chứa toàn bộ logic để điều khiển ứng dụng - tệp này được sinh ra từ mã của nhà phát triển
Với các yêu cầu như trên, chúng ta nên sắp xếp để tải các tệp Javascript như thế nào để tốc độ tải tệp là tốt nhất?
2. Chuẩn bị môi trường
Để giả lập thời gian tải các tệp JS, chúng tôi sẽ tạo ra một tệp
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
6 có nội dung như sauconst express = require['express'];
const app = express[];
const port = 3000;
app.use[function [req, res, next] {
const timeout = req.query.timeout || 0;
setTimeout[next, timeout];
}];
app.get['/index.js', [req, res] => {
const env = req.query.env || 'web';
const timeout = req.query.timeout || 0;
res.header['Content-type', 'text/javascript'];
res.header['cache-control', 'max-age=604800'];
res.send[
`console.log["hello world ${timeout} from ${env} at", Date.now[] - self.START_TIME];`
];
}];
app.listen[port, [] => {
console.log[
`Example app listening at //localhost:${port}`
];
}];
Sao chépTrong đoạn mã kể trên, chúng ta tạo ra một máy chủ chạy ở cổng 3000
Máy chủ này cho phép chúng ta truy vấn vào tệp
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
7. Tệp console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
7 nhận vào 2 tham số
9 là thời gian giả lập để máy chủ có thể trả về nội dung của tệp,console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
9 được tính bằng giây. VD.console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
1, tức là máy chủ sẽ mất 1 giây để trả về tệp nội dungconsole.log[
'hello world 1 from web',
Date.now[] - self.START_TIME
];
2 là môi trường mà kịch bản này sẽ được chạy, mặc định làconsole.log[
'hello world 1 from web',
Date.now[] - self.START_TIME
];
3. on the value ofconsole.log[
'hello world 1 from web',
Date.now[] - self.START_TIME
];
2 that fileconsole.log[
'hello world 1 from web',
Date.now[] - self.START_TIME
];
7 will be return on the content as afterconsole.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
Sao chépVí dụ. when request to
console.log[
'hello world 1 from web',
Date.now[] - self.START_TIME
];
6, server will return on contentconsole.log[
'hello world 1 from web',
Date.now[] - self.START_TIME
];
Sao chépỞ đây, chúng ta giả vờ rằng các script trước đó đã khởi tạo sẵn một biến toàn cầu tên là
console.log[
'hello world 1 from web',
Date.now[] - self.START_TIME
];
7. Vì vậy, khi tập lệnh trên được chạy, tập lệnh có thể cho chúng ta biết, thời gian mà tập lệnh được trình duyệt đánh giá3. Tải Javascript trên Chủ đề chính
Để giả lập việc tải tệp trên Chủ đề chính, chúng ta sẽ tạo chỉ mục cho tệp. html as after
7Sao chép
Trong thẻ
console.log[
'hello world 1 from web',
Date.now[] - self.START_TIME
];
8, chúng ta chạy đoạn script để khởi động biến console.log[
'hello world 1 from web',
Date.now[] - self.START_TIME
];
7. Sau đó, chúng ta đặt các thẻ 70 ở cuối thẻ
71, mục đích là để trình duyệt khi tải tập lệnh thẻ này sẽ không chặn nội dung của
71 trả về
Ở đây chúng ta load 2 script, script đầu tiên mất 2s để load, còn script tiếp theo chỉ tiền duy nhất 1s
Câu hỏi là, thời gian để trình duyệt tải xuống 2 tập lệnh trên sẽ là bao nhiêu?
Chúc mừng bạn, nếu câu trả lời của bạn là 2s. Bạn đã rất hiểu cách trình duyệt tải các tập lệnh đó. Trong giai đoạn phân tích cú pháp HTML, trình duyệt sẽ phát ra trang web này cần phải tải 2 tập lệnh. Và trình duyệt sẽ thực hiện tải 2 script này song song với nhau. Sau khi tải xong, trình duyệt mới thực hiện đánh giá các tập lệnh theo thứ tự mà chúng sắp xếp. Trong trường hợp này, mặc dù script với
console.log[
'hello world 1 from web',
Date.now[] - self.START_TIME
];
1 dù được tải xuống xong trước script với 74, tuy nhiên, do script với
74 sắp xếp trước, nên code của script với
74 vẫn được chạy trước
Browser will in ra console content as after
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
7Sao chépChú thích. để kiểm tra hành vi đúng của trình duyệt, chúng ta cần chắc chắn rằng chỉ mục tải tệp là. html trên môi trường ẩn danh không có bộ nhớ cache của các yêu cầu, bởi vì sau khi các yêu cầu đã được lưu lại bộ nhớ cache rồi, thời gian tải xuống các yêu cầu sẽ không còn đúng nữa
4. Tải Javascript trên Worker
Trên Chủ đề chính, trình duyệt sẽ tải các tập lệnh song song với nhau, vậy khi tải các tập lệnh trên Web Worker thì sao?
Để tải tập lệnh trên Web Worker, chúng ta có 2 tình huống
- khởi tạo tập lệnh cho một Web Worker. Đây là tập lệnh được sử dụng để khởi động Web Worker, chúng ta sẽ tải tập lệnh này thông qua việc sử dụng hàm
- sau khi Web Worker được tạo ra, Web Worker có thể có nhu cầu muốn tải thêm các tập lệnh khác
2 tình huống này sẽ có những cách xử lý khác nhau
4. 1. Load scripts to start Web Worker
Để khởi tạo một Web Worker, chúng ta sẽ sử dụng hàm
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
9Sao chépĐể kiểm tra xem trình duyệt sẽ thực hiện việc tải url tập lệnh của Web Worker như thế nào, chúng ta chuẩn bị đoạn mã như sau
const express = require['express'];
const app = express[];
const port = 3000;
app.use[function [req, res, next] {
const timeout = req.query.timeout || 0;
setTimeout[next, timeout];
}];
app.get['/index.js', [req, res] => {
const env = req.query.env || 'web';
const timeout = req.query.timeout || 0;
res.header['Content-type', 'text/javascript'];
res.header['cache-control', 'max-age=604800'];
res.send[
`console.log["hello world ${timeout} from ${env} at", Date.now[] - self.START_TIME];`
];
}];
app.listen[port, [] => {
console.log[
`Example app listening at //localhost:${port}`
];
}];
0Sao chépTại đây, chúng ta giả lập tải một file worker. js ở cuối cùng, sau khi đã tải được các tệp js ở Chủ đề chính. File worker này mất 1s để tải xuống. Sau khi Web Worker được khởi động, Main Thread sẽ gửi một thông báo tới Worker để gửi thời gian mà Main Thread bắt đầu. Trên Worker, chúng ta sẽ kiểm tra thời gian mà Web Worker bắt đầu được chạy, từ khoảng thời gian này chúng ta có thể biết được trình duyệt đã thực hiện việc tải xuống Worker scripts ra sao
Tệp
78 có nội dung như sau
const express = require['express'];
const app = express[];
const port = 3000;
app.use[function [req, res, next] {
const timeout = req.query.timeout || 0;
setTimeout[next, timeout];
}];
app.get['/index.js', [req, res] => {
const env = req.query.env || 'web';
const timeout = req.query.timeout || 0;
res.header['Content-type', 'text/javascript'];
res.header['cache-control', 'max-age=604800'];
res.send[
`console.log["hello world ${timeout} from ${env} at", Date.now[] - self.START_TIME];`
];
}];
app.listen[port, [] => {
console.log[
`Example app listening at //localhost:${port}`
];
}];
2Sao chépNếu nhìn vào bảng điều khiển của trình duyệt, chúng ta sẽ thấy nội dung như sau
const express = require['express'];
const app = express[];
const port = 3000;
app.use[function [req, res, next] {
const timeout = req.query.timeout || 0;
setTimeout[next, timeout];
}];
app.get['/index.js', [req, res] => {
const env = req.query.env || 'web';
const timeout = req.query.timeout || 0;
res.header['Content-type', 'text/javascript'];
res.header['cache-control', 'max-age=604800'];
res.send[
`console.log["hello world ${timeout} from ${env} at", Date.now[] - self.START_TIME];`
];
}];
app.listen[port, [] => {
console.log[
`Example app listening at //localhost:${port}`
];
}];
3Sao chépĐiều này có nghĩa là. tại thời điểm trình duyệt nhận được chỉ thị
79, trình duyệt mới bắt đầu thực hiện việc tải xuống tập lệnh
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
70Do đó, trình duyệt sẽ phải mất 3s để tải xuống cả 3 tập lệnh [bao gồm 2 tập lệnh
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
71, console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
72 và console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
73]Vì vậy, có cách nào để chúng tôi thông báo cho trình duyệt tải xuống tệp
78 trước khi chúng tôi khởi tạo Web Worker không?
Ở đây chúng ta có thể nghĩ đến 2 giải pháp, sử dụng thẻ
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
75 để thông báo cho trình duyệt rằng chúng ta cần tải [download + parse] tệp 78 trước, hoặc sử dụng thẻ
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
77 để thông báo cho trình duyệt rằng chúng tôi cần tải xuống tệp 78 trước
Do
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
79 không hỗ trợ loại tệp tải cho worker khởi tạo tệp, nên chúng tôi sử dụng thẻ console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
90Chúng ta sửa lại đoạn mã html như sau
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
6Sao chépSau khi chạy xong, chúng ta có thể thấy giao diện điều khiển có nội dung như sau
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
0Sao chépTuy nhiên, đáng buồn là khi sử dụng
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
90 và console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
79 để tải worker, thì cách làm này chỉ hoạt động với Chrome, còn không hoạt động với iOS. Trên iOS, tôi cũng không biết có cách nào tốt hơn để tải các tệp worker không. Nếu các bạn biết vui lòng chia sẻ cho mình với nhéMột điểm rất hay của Chrome khi sử dụng
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
90 đó là Chrome đủ thông minh để tận dụng lại các yêu cầu. Ví dụ, nếu thời gian để tải xuống 78 thay vì chỉ cần 1s, mà thành 4s, thì tại thời điểm trình duyệt nhận được chỉ thị
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
95, yêu cầu console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
90 vẫn chưa hoàn thành. Dù vậy, Chrome sẽ không tạo yêu cầu mới nữa, mà đợi yêu cầu console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
90 thực hiện xong rồi sử dụng kết quả của yêu cầu này để chạy tiếpDo đó, bằng cách sử dụng
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
90, chúng ta có thể chắc chắn rằng các tệp JS được tải xuống bài hát song song với nhau trên Chủ đề chính [tuy nhiên Trình duyệt vẫn giới hạn số lượng yêu cầu có thể tải xuống bài hát song song với nhau, mặc định chỉ Chrome Do đó, nhìn chung để Web Worker có thể bắt đầu nhanh nhất có thể trên cả Android và iOS, cách làm tốt nhất vẫn là nên khởi tạo Web Worker càng sớm càng tốt
4. 2. Tải tập lệnh trong Web Worker
Trong Web Worker, để có thể nhập được một tập lệnh, chúng tôi sử dụng hàm
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
99Ví dụ, với tệp
78 ở trên, chúng tôi muốn tải 2 tệp
const express = require['express'];
const app = express[];
const port = 3000;
app.use[function [req, res, next] {
const timeout = req.query.timeout || 0;
setTimeout[next, timeout];
}];
app.get['/index.js', [req, res] => {
const env = req.query.env || 'web';
const timeout = req.query.timeout || 0;
res.header['Content-type', 'text/javascript'];
res.header['cache-control', 'max-age=604800'];
res.send[
`console.log["hello world ${timeout} from ${env} at", Date.now[] - self.START_TIME];`
];
}];
app.listen[port, [] => {
console.log[
`Example app listening at //localhost:${port}`
];
}];
01 và const express = require['express'];
const app = express[];
const port = 3000;
app.use[function [req, res, next] {
const timeout = req.query.timeout || 0;
setTimeout[next, timeout];
}];
app.get['/index.js', [req, res] => {
const env = req.query.env || 'web';
const timeout = req.query.timeout || 0;
res.header['Content-type', 'text/javascript'];
res.header['cache-control', 'max-age=604800'];
res.send[
`console.log["hello world ${timeout} from ${env} at", Date.now[] - self.START_TIME];`
];
}];
app.listen[port, [] => {
console.log[
`Example app listening at //localhost:${port}`
];
}];
02, chúng tôi sẽ làm như sauconsole.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
1Sao chépỞ đây chúng ta thực hiện việc tải các tập lệnh sau khi nhận được thông báo từ Main Thead
Chú ý rằng hàm
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
99 là hàm đồng bộ, tức là khi hàm này chạy, trình duyệt phải đợi các script tải xong thì mới tiếp tục chạy các lệnh tiếp theo. Vì vậy với đoạn mã ở trên, chúng ta sẽ phải mất 700 mili giây để tải xuống tất cả các tập lệnhĐoạn mã sẽ hiển thị trong màn hình nội dung như sau
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
2Sao chépĐể giảm thời gian tải xuống, chúng ta có thể tiếp tục sử dụng
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
90console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
3Sao chépSau khi sử dụng
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
90, bảng điều khiển sẽ có nội dung như sauconsole.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
4Sao chépTuy nhiên, cũng giống như ở phần 4. 1,
console.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
90 không có tác dụng với iOS. Vì cách tốt hơn để nhập tập lệnh trong Worker đó là chúng ta tự viết một hàm nhập riêngconsole.log[
'hello world ${timeout} from ${env}',
Date.now[] - self.START_TIME
];
5Sao chépTại đây, chúng ta thực hiện tải xuống các tập lệnh song song với nhau bằng cách khởi động các yêu cầu XHR riêng biệt. Sau khi download script xong, chúng ta mới đánh giá các script này. Bằng cách này, chúng ta có thể chắc chắn rằng trong một Web Worker, các tập lệnh có thể có thời gian tải xuống nhanh nhất có thể
Kết luận
Thông qua bài viết này, chúng tôi đã xem xét một số phương án để làm sao có thể tải các tệp Javascript trong Main Thread và trong Web Worker nhanh nhất có thể