คำนำ
ฉันเชื่อว่าทุกคนพบปัญหามากมายเกี่ยวกับการโหลดสคริปต์ JavaScript ส่วนใหญ่มีหลายจุด -
1> ปัญหาเกี่ยวกับการโหลดไฟล์การพึ่งพาไฟล์และลำดับการดำเนินการที่เกิดจากสคริปต์แบบซิงโครนัสและสคริปต์แบบอะซิงโครนัส
2> ปัญหาการเพิ่มประสิทธิภาพประสิทธิภาพที่เกิดจากสคริปต์แบบซิงโครนัสและสคริปต์แบบอะซิงโครนัส
ความเข้าใจอย่างลึกซึ้งเกี่ยวกับการโหลดสคริปต์ทุกด้านไม่เพียง แต่เอื้อต่อการแก้ปัญหาการปฏิบัติ แต่ยังเอื้อต่อการเข้าใจและดำเนินการเพิ่มประสิทธิภาพประสิทธิภาพ
ก่อนอื่นดูรหัสแท็กสคริปต์ใด ๆ -
การคัดลอกรหัสมีดังนี้:
<script src = "js/myapp.js"> </script>
หากวางไว้บน <head> มันจะปิดกั้นงานการเรนเดอร์หน้าทั้งหมดทำให้ผู้ใช้ยังคงอยู่ในสถานะ "หน้าจอสีขาวแห่งความตาย" จนกว่าสคริปต์จะถูกโหลดและดำเนินการ สคริปต์ในตอนท้ายของ <body> จะให้ผู้ใช้เห็นหน้าคงที่โดยไม่มีพลัง ในกรณีที่การแสดงผลของลูกค้าควรจะกระจัดกระจายไปด้วยการควบคุมที่ไม่มีประสิทธิภาพและกล่องเปล่า ใช้กรณีทดสอบ -
การคัดลอกรหัสมีดังนี้:
<! doctype html>
<html>
<head lang = "en">
<meta charset = "utf-8">
<title> สคริปต์การโหลด async </title>
<script src = "js/test.js"> </script>
</head>
<body>
<div> ฉันเป็นเนื้อหา </div>
<img src = "img/test.jpg">
</body>
</html>
ในหมู่พวกเขาเนื้อหาใน test.js -
การคัดลอกรหัสมีดังนี้:
การแจ้งเตือน ('ฉันเป็นรหัสสคริปต์ในหัวหลังจากดำเนินการ JS ที่นี่การเรนเดอร์เนื้อหาร่างกายจะเริ่มขึ้น!');
เราจะเห็นว่าการแจ้งเตือนเป็นจุดหยุดชั่วคราวและในเวลานี้หน้านั้นว่างเปล่า อย่างไรก็ตามโปรดทราบว่าทั้งหน้าถูกโหลดในเวลานี้ หากร่างกายมีแท็กสำหรับแอตทริบิวต์ SRC บางอย่าง (เช่นแท็ก IMG ด้านบน) เบราว์เซอร์ได้เริ่มโหลดเนื้อหาที่เกี่ยวข้องในเวลานี้ ในระยะสั้นควรสังเกตว่าช่วงเวลาการทำงานของเครื่องยนต์ JS และเอ็นจิ้นเรนเดอร์นั้นเป็นเอกสิทธิ์เฉพาะบุคคล (หนังสือบางเล่มเรียกว่าเธรด UI)
ดังนั้นเราต้องการสคริปต์ที่รับผิดชอบในการทำให้หน้าดูดีขึ้นและใช้งานได้ดีขึ้นควรโหลดทันทีและสคริปต์ที่สามารถโหลดได้ในภายหลังจะถูกโหลดในภายหลัง
1. ความล่าช้าในการดำเนินการสคริปต์
ตอนนี้มันกลายเป็นที่นิยมมากขึ้นเรื่อย ๆ ในการวางสคริปต์ในตอนท้ายของแท็ก <body> ด้วยวิธีนี้ในอีกด้านหนึ่งผู้ใช้สามารถเห็นหน้าเว็บได้เร็วขึ้นและในทางกลับกันสคริปต์สามารถใช้งานองค์ประกอบ DOM ที่โหลดได้โดยตรง "การเคลื่อนไหว" นี้เป็นการปรับปรุงครั้งใหญ่สำหรับสคริปต์ส่วนใหญ่ โมเดลหน้ามีดังนี้ -
การคัดลอกรหัสมีดังนี้:
<! doctype html>
<html>
<head lang = "en">
<!-ข้อมูลเมตาและ scriptsheets ไปที่นี่->
<script src = "headscript.js"> </script>
</head>
<body>
<!-เนื้อหาไปที่นี่->
<script src = "bodyscript.js"> </script>
</body>
</html>
สิ่งนี้จะช่วยเพิ่มความเร็วในการแสดงผลของหน้าอย่างมาก แต่โปรดทราบว่าสิ่งนี้อาจเปิดโอกาสให้ผู้ใช้โต้ตอบกับหน้าเว็บก่อนที่จะโหลด BodyScript เหตุผลที่เบราว์เซอร์ไม่สามารถโหลดสคริปต์ก่อนที่จะโหลดเอกสารฉบับเต็มเป็นคอขวดขนาดใหญ่สำหรับเอกสารขนาดใหญ่ที่ส่งผ่านการเชื่อมต่อที่ช้า
เป็นการดีที่การโหลดสคริปต์ควรทำพร้อมกันกับการโหลดเอกสารและไม่ส่งผลกระทบต่อการเรนเดอร์ของ DOM ด้วยวิธีนี้เมื่อเอกสารพร้อมแล้วสคริปต์สามารถเรียกใช้ได้เนื่องจากสคริปต์ที่เกี่ยวข้องถูกโหลดตามลำดับของแท็ก <Script>
เราสามารถทำตามข้อกำหนดนี้ได้โดยใช้การเลื่อนเวลานั่นคือ
การคัดลอกรหัสมีดังนี้:
<script src = "deverredscript.js"> </script>
การเพิ่มแอตทริบิวต์การเลื่อนเวลานั้นเทียบเท่ากับการบอกเบราว์เซอร์: โปรดเริ่มโหลดสคริปต์นี้ทันที แต่โปรดรอจนกว่าเอกสารจะพร้อมและสคริปต์ทั้งหมดที่มีแอตทริบิวต์เลื่อนเวลาทำงานเสร็จก่อนที่จะทำงาน
ด้วยวิธีนี้การวางสคริปต์ความล่าช้าในแท็กหัวจะนำประโยชน์ทั้งหมดของการวางสคริปต์ไว้บนแท็กตัวถังและสามารถปรับปรุงความเร็วในการโหลดของเอกสารขนาดใหญ่ได้อย่างมาก โหมดหน้าในเวลานี้คือ -
การคัดลอกรหัสมีดังนี้:
<! doctype html>
<html>
<head lang = "en">
<!-ข้อมูลเมตาและ scriptsheets ไปที่นี่->
<script src = "headscript.js"> </script>
<script src = "deverredscript.js" defer> </script>
</head>
<body>
<!-เนื้อหาไปที่นี่->
</body>
</html>
อย่างไรก็ตามเบราว์เซอร์ทั้งหมดไม่สนับสนุนการเลื่อนเวลา (สำหรับเบราว์เซอร์ที่ทันสมัยบางอย่างหากมีการประกาศการเลื่อนเวลาสคริปต์ภายในของพวกเขาจะไม่ดำเนินการ document.write และการดำเนินการเรนเดอร์ DOM ทั้งสอง IE4+ สนับสนุนแอตทริบิวต์การเลื่อนเวลา) ซึ่งหมายความว่าหากคุณต้องการให้แน่ใจว่าสคริปต์ความล่าช้าของคุณสามารถรันได้หลังจากโหลดเอกสารคุณต้องห่อหุ้มรหัสของสคริปต์การหน่วงเวลาทั้งหมดในโครงสร้างเช่น $ (เอกสาร) ของ jQuery สิ่งนี้คุ้มค่าเพราะเกือบ 97% ของผู้เข้าชมสามารถเพลิดเพลินไปกับประโยชน์ของการโหลดแบบขนานในขณะที่อีก 3% ของผู้เข้าชมยังสามารถใช้จาวาสคริปต์ที่มีคุณสมบัติเต็มรูปแบบ
2. สคริปต์แบบขนานที่สมบูรณ์
ปล่อยให้สคริปต์ถูกโหลดและดำเนินการเร็วขึ้นหนึ่งก้าว ฉันไม่ต้องการรอจนกว่าสคริปต์เลื่อนเวลาจะทำงานหนึ่งหลังจากนั้น (เลื่อนเวลาเตือนเราถึงสถานการณ์การเข้าคิวที่สั่งซื้อซึ่งเอกสารกำลังรอให้เอกสารโหลดอย่างเงียบ ๆ ) และฉันไม่ต้องการรอจนกว่าเอกสารจะพร้อมก่อนที่จะเรียกใช้สคริปต์เหล่านี้ ฉันต้องการโหลดและเรียกใช้สคริปต์เหล่านี้โดยเร็วที่สุด ที่นี่เราคิดถึงแอตทริบิวต์ async ของ HTML5 แต่โปรดทราบว่ามันเป็นอนาธิปไตยที่วุ่นวาย
ตัวอย่างเช่นเราโหลดสคริปต์ของบุคคลที่สามที่ไม่เกี่ยวข้องอย่างสมบูรณ์สองรายการและหน้าเว็บทำงานได้ดีหากไม่มีพวกเขาและไม่สนใจว่าใครจะทำงานก่อนและผู้ที่ทำงานในภายหลัง ดังนั้นการใช้แอตทริบิวต์ async บนสคริปต์ของบุคคลที่สามเหล่านี้เทียบเท่ากับการปรับปรุงความเร็วในการทำงานโดยไม่ต้องใช้เงิน
แอตทริบิวต์ ASYNC จะถูกเพิ่มเข้ามาใหม่ใน HTML5 ฟังก์ชั่นนั้นคล้ายกับการเลื่อนเวลานั่นคือมันช่วยให้การเรนเดอร์ DOM ขณะดาวน์โหลดสคริปต์ อย่างไรก็ตามมันจะถูกดำเนินการโดยเร็วที่สุดหลังจากดาวน์โหลด (เช่นเอ็นจิ้น JS ไม่ได้ใช้งานและดำเนินการทันที) และไม่มีการรับประกันว่าสคริปต์จะถูกดำเนินการตามลำดับ พวกเขาจะแล้วเสร็จก่อนเหตุการณ์ ONLOAD
Firefox 3.6, Opera 10.5, IE 9 และ Chrome ล่าสุดและ Safari ทั้งหมดสนับสนุนแอตทริบิวต์ Async Async และ Async สามารถใช้งานได้ในเวลาเดียวกันเพื่อให้ IEs ทั้งหมดหลังจาก IE 4 สนับสนุนการโหลดแบบอะซิงโครนัส แต่ระวังว่า Async จะเขียนทับ
จากนั้นโมเดลหน้าในเวลานี้มีดังนี้ -
การคัดลอกรหัสมีดังนี้:
<! doctype html>
<html>
<head lang = "en">
<!-ข้อมูลเมตาและ scriptsheets ไปที่นี่->
<script src = "headscript.js"> </script>
<script src = "deverredscript.js" defer> </script>
</head>
<body>
<!-เนื้อหาไปที่นี่->
<script src = "asyncscript1.js" async defer> </script>
<script src = "asyncscript2.js" async defer> </script>
</body>
</html>
ให้ความสนใจกับคำสั่งการดำเนินการที่นี่ - ไฟล์สคริปต์แต่ละไฟล์จะถูกโหลดจากนั้น headscript.js จะถูกดำเนินการและจากนั้น defferedscript.js จะถูกโหลดในพื้นหลังในขณะที่การเรนเดอร์ DOM จากนั้น defferedscript.js และสคริปต์แบบอะซิงโครนัสทั้งสองจะทำงานในตอนท้ายของการแสดงผล DOM โปรดทราบว่าสำหรับเบราว์เซอร์ที่รองรับแอตทริบิวต์ Async สคริปต์ทั้งสองนี้จะหมดการสั่งซื้อ
3. การโหลดสคริปต์ที่ตั้งโปรแกรมได้
แม้ว่าฟังก์ชั่นของคุณสมบัติสคริปต์สองตัวข้างต้นนั้นน่าสนใจมาก แต่ก็ไม่ได้ใช้กันอย่างแพร่หลายเนื่องจากปัญหาความเข้ากันได้ ดังนั้นเราใช้สคริปต์เพื่อโหลดสคริปต์อื่น ๆ มากขึ้น ตัวอย่างเช่นเราต้องการโหลดสคริปต์สำหรับผู้ใช้ที่ตรงตามเงื่อนไขบางประการซึ่งมักจะกล่าวถึง "ขี้เกียจโหลด"
ที่ระดับเบราว์เซอร์ API มีสองวิธีที่เหมาะสมในการรวบรวมข้อมูลและเรียกใช้สคริปต์เซิร์ฟเวอร์ -
1> สร้างคำขอ AJAX และใช้ฟังก์ชั่น eval เพื่อประมวลผลการตอบกลับ
2> แทรกแท็ก <Script> ลงใน DOM
วิธีหลังดีกว่าเพราะเบราว์เซอร์จะกังวลเกี่ยวกับการสร้างคำขอ HTTP สำหรับเรา นอกจากนี้ Eval ยังมีปัญหาในทางปฏิบัติบางอย่างเช่นขอบเขตการรั่วไหลการดีบักนั้นยุ่งเหยิงและอาจลดประสิทธิภาพได้ ดังนั้นหากคุณต้องการโหลดสคริปต์ชื่อ Feature.js เราควรใช้รหัสดังต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
var head = document.getElementsByTagname ('head') [0];
var script = document.createElement ('script');
script.src = 'feature.js';
head.appendchild (สคริปต์);
แน่นอนว่าเราต้องจัดการกับการฟังการโทรกลับและข้อกำหนด HTML5 กำหนดคุณสมบัติ ONLOAD ที่สามารถผูกการโทรกลับ
การคัดลอกรหัสมีดังนี้:
script.onload = function () {
console.log ('สคริปต์โหลด ... ');
-
อย่างไรก็ตาม IE8 และรุ่นเก่าไม่รองรับ OnLoad พวกเขารองรับ OnreadyStateChange ยิ่งไปกว่านั้นยังมีสิ่งแปลก ๆ อีกมากมายที่จะจัดการกับข้อผิดพลาด ที่นี่คุณสามารถอ้างถึงห้องสมุดโหลดที่ใช้โรงเรียนยอดนิยมเช่น Labjs, Yepnope, Requirejs ฯลฯ
ดังต่อไปนี้ฉันห่อหุ้มไฟล์ loadjs อย่างง่ายด้วยตัวเอง -
การคัดลอกรหัสมีดังนี้:
var loadjs = function (url, callback) {
var head = document.getElementsByTagname ('head') [0];
var script = document.createElement ('script');
script.src = url;
script.type = "text/javascript";
head.appendchild (สคริปต์);
// แท็กสคริปต์มีเหตุการณ์ onreadystatechange ภายใต้ IE และมีเหตุการณ์ ONLOAD ภายใต้มาตรฐาน W3C
// IE9+ ยังรองรับ ONLoad ของมาตรฐาน W3C
var ua = navigator.useragent,
ua_version;
// IE6/7/8
if (/msie ([^;]+)/. ทดสอบ (ua)) {
ua_version = parsefloat (regexp ["$ 1"], 10);
if (ua_version <= 8) {
script.onreadyStateChange = function () {
if (this.readystate == "โหลด") {
การโทรกลับ ();
-
-
} อื่น {
script.onload = function () {
การโทรกลับ ();
-
-
} อื่น {
script.onload = function () {
การโทรกลับ ();
-
-
-
ฉันจะไม่พูดถึงการโหลดสคริปต์แบบอะซิงโครนัสใน document.write ตอนนี้มีเพียงไม่กี่คนที่ทำเช่นนี้เพราะเบราว์เซอร์แตกต่างกันมาก
โปรดทราบว่าการใช้อ็อบเจ็กต์ภาพเพื่อโหลดไฟล์ js ล่วงหน้าแบบอะซิงโครนัสรหัส JS ภายในจะไม่ถูกดำเนินการ
สุดท้ายเรามาพูดคุยเกี่ยวกับสคริปต์การโหลดแบบอะซิงโครนัสใน RequireJS
RequireJS ไม่รับประกันว่าสคริปต์เป้าหมายจะทำงานตามลำดับ แต่มั่นใจได้ว่าคำสั่งซื้อของพวกเขาสามารถปฏิบัติตามข้อกำหนดการพึ่งพาได้ตามลำดับ ดังนั้นเราจึงมั่นใจได้ว่าสคริปต์ทั้งหมดจะถูกโหลดแบบขนานโดยเร็วที่สุดและดำเนินการอย่างเป็นระเบียบตามทอพอโลยีการพึ่งพา
4. สรุป
ตกลงเมื่อพูดถึงเรื่องนี้คำสั่งของสคริปต์การโหลดแบบอะซิงโครนัสสิ้นสุดลง ให้ฉันพูดถึงคำสั่งการเพิ่มประสิทธิภาพที่นี่อีกครั้ง -
1> ด้วยวิธีดั้งเดิมเราใช้แท็กสคริปต์เพื่อฝังลงในเอกสาร HTML โดยตรง นี่คือสองสถานการณ์ -
A> ฝังลงในแท็กหัว - ระวังว่าการทำเช่นนั้นจะไม่ส่งผลกระทบต่อการโหลดแบบขนานของไฟล์ทรัพยากรคงที่อื่น ๆ ในเนื้อหาเอกสาร มันมีผลต่อการเรนเดอร์ของเนื้อหาเอกสารนั่นคือการแสดงผล DOM ในเวลานี้จะถูกบล็อกและหน้าจอสีขาวจะถูกนำเสนอ
B> ฝังที่ด้านล่างของแท็กตัวถัง - เพื่อหลีกเลี่ยงปรากฏการณ์หน้าจอสีขาวเราให้ความสำคัญกับการแสดงผล DOM จากนั้นเรียกใช้สคริปต์ แต่ปัญหามาอีกครั้ง มาพูดถึงคำถามแรกก่อน - หากเนื้อหาของเอกสาร DOM ค่อนข้างใหญ่การเชื่อมโยงเหตุการณ์การโต้ตอบจะล่าช้าและประสบการณ์จะแย่ลงเล็กน้อย แน่นอนเราต้องทำให้สคริปต์ที่สำคัญดำเนินการก่อนตามความต้องการ มาพูดคุยเกี่ยวกับปัญหาที่สอง - เนื่องจากไฟล์สคริปต์อยู่ที่ด้านล่างของร่างกายการโหลดสคริปต์เหล่านี้ล่าช้าเมื่อเทียบกับสคริปต์ในหัว ดังนั้นสำหรับด้านล่างของร่างกายมันไม่ใช่จุดสิ้นสุดของการเพิ่มประสิทธิภาพ
C> เพิ่มแอตทริบิวต์การเลื่อนเวลา - เราหวังว่าสคริปต์จะโหลดแบบขนานโดยเร็วที่สุดและเราจะยังคงใส่สคริปต์ชุดนี้ลงในหัว การโหลดสคริปต์ควรทำพร้อมกันกับการโหลดเอกสารและไม่ส่งผลกระทบต่อการเรนเดอร์ของ DOM ด้วยวิธีนี้สคริปต์สามารถเรียกใช้ได้เมื่อเอกสารพร้อม ดังนั้นจึงมีคุณลักษณะที่เลื่อนออกไป แต่ให้ความสนใจกับความเข้ากันได้ สำหรับเบราว์เซอร์ที่ไม่รองรับแอตทริบิวต์การเลื่อนเวลาเราต้องห่อหุ้มรหัสใน $ (เอกสาร) พร้อมเช่น jQuery ควรสังเกตว่าสคริปต์ทั้งหมดที่มีแอตทริบิวต์เลื่อนออกจะถูกดำเนินการตามลำดับตามลำดับการปรากฏตัวของพวกเขาดังนั้นพวกเขาจึงถูกซิงโครไนซ์อย่างเคร่งครัด
2> จุดก่อนหน้านี้เกี่ยวกับสคริปต์การดำเนินการแบบซิงโครนัส (โปรดทราบว่ากระบวนการโหลดของสคริปต์เหล่านี้ขนานกัน แต่ความแตกต่างระหว่างผู้ที่เรียกร้องให้มีการร้องขอก่อนและผู้ที่เรียกร้องให้มีการร้องขอ) จุดเพิ่มประสิทธิภาพครั้งต่อไปคือ "สคริปต์การดำเนินการแบบขนาน" แน่นอนเรารู้ว่า ณ จุดหนึ่งมีการเรียกใช้ไฟล์ JS เพียงไฟล์เดียวเท่านั้น "ขนาน" ที่นี่หมายความว่าใครก็ตามที่โหลดก่อนตราบใดที่เครื่องยนต์ JS ไม่ได้ใช้งานในเวลานี้มันจะถูกดำเนินการทันที การเพิ่มประสิทธิภาพที่นี่แบ่งออกเป็นสองประเภท -
A> การเพิ่มคุณสมบัติ async - มันสามารถทำให้จุดเพิ่มประสิทธิภาพที่เรากล่าวถึงข้างต้นได้อย่างแท้จริง แต่มันมีข้อ จำกัด สูงนั่นคือมันเป็นเพียงการโหลดสคริปต์ที่ไม่พึ่งพาอาศัยกัน ตัวอย่างที่เหมาะสมที่สุดคือการแนะนำสคริปต์ของบุคคลที่สามหลายรายการ นอกจากนี้การรวมกันกับแอตทริบิวต์ Deffer นั้นเป็นเรื่องใหญ่จริงๆ แน่นอนว่ามันยังมีปัญหาความเข้ากันได้ ปัญหาสามประการข้างต้นนำไปสู่การใช้งานไม่บ่อยนัก เมื่อใช้ ASYNC คุณต้องใส่ใจกับปัญหาการพึ่งพา
B> สคริปต์การโหลดสคริปต์ - เห็นได้ชัดว่าเราใช้สิ่งนี้เพื่อให้บรรลุวัตถุประสงค์ของ "การดำเนินการแบบขนานของสคริปต์" ในเวลาเดียวกันเรายังอำนวยความสะดวกในการควบคุมการพึ่งพาสคริปต์ดังนั้นเราจึงใช้การจัดการโหลดอัจฉริยะสำหรับการโหลดแบบอะซิงโครนัสใน reghejs
ตกลงนั่นคือทั้งหมด
ที่นี่ฉันแค่พูดถึงเนื้อหาที่เกี่ยวข้องกับสคริปต์การโหลดแบบอะซิงโครนัส มีอีกส่วนหนึ่งของเนื้อหาซึ่งเป็นการโหลดแบบอะซิงโครนัสของไฟล์สไตล์หรือทรัพยากรคงที่อื่น ๆ จะดำเนินการต่อ ......