สคริปต์ของบุคคลที่สามส่งผลกระทบต่อประสิทธิภาพ คุณจึงต้องตรวจสอบสคริปต์ดังกล่าวเป็นประจำและใช้เทคนิคที่มีประสิทธิภาพในการโหลด Codelab นี้แสดงวิธีเพิ่มประสิทธิภาพการโหลดทรัพยากรของบุคคลที่สาม โดยจะอธิบายเทคนิคต่อไปนี้
กำลังเลื่อนการโหลดสคริปต์
การโหลดแบบ Lazy Loading ทรัพยากรที่ไม่สำคัญ
เชื่อมต่อกับต้นทางที่จำเป็นล่วงหน้า
แอปตัวอย่างที่รวมไว้นำเสนอหน้าเว็บที่เรียบง่ายพร้อมด้วยฟีเจอร์ 3 อย่างที่มาจากแหล่งข้อมูลของบุคคลที่สาม ดังนี้
วิดีโอที่ฝัง
ไลบรารีการแสดงข้อมูลผ่านภาพสำหรับแสดงผลกราฟเส้น
วิดเจ็ตการแชร์ผ่านโซเชียลมีเดีย
![ภาพหน้าจอของหน้าเว็บที่ไฮไลต์ทรัพยากรของบุคคลที่สาม](https://web.dev/static/articles/codelab-optimize-third-party-javascript/image/screenshot-the-page-thi-cc10c15b4c9aa.png?authuser=5&hl=th)
คุณจะเริ่มต้นด้วยการวัดประสิทธิภาพของแอป จากนั้นจึงใช้เทคนิคแต่ละเทคนิคเพื่อปรับปรุงประสิทธิภาพของแอปในด้านต่างๆ
วัดประสิทธิภาพ
ก่อนอื่นให้เปิดแอปตัวอย่างในมุมมองแบบเต็มหน้าจอ โดยทำดังนี้
- คลิกรีมิกซ์เพื่อแก้ไขเพื่อทำให้โปรเจ็กต์แก้ไขได้
- หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ
เรียกใช้การตรวจสอบประสิทธิภาพของ Lighthouse ในหน้าเว็บเพื่อสร้างประสิทธิภาพพื้นฐาน ดังนี้
- กด "Control+Shift+J" (หรือ "Command+Option+J" ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาเว็บ
- คลิกแท็บ Lighthouse
- คลิกอุปกรณ์เคลื่อนที่
- เลือกช่องทำเครื่องหมายประสิทธิภาพ (คุณสามารถล้างช่องทำเครื่องหมายที่เหลือได้ในส่วนการตรวจสอบ)
- คลิก 3G แบบรวดเร็วจำลอง, ความเร็ว CPU ช้าลง 4 เท่า
- เลือกช่องทำเครื่องหมายล้างพื้นที่เก็บข้อมูล
- คลิกดำเนินการตรวจสอบ
เมื่อทำการตรวจสอบบนเครื่อง ผลลัพธ์ที่แน่นอนอาจแตกต่างกันไป แต่คุณควรสังเกตเห็นว่าเวลา First Contentful Paint (FCP) ค่อนข้างสูง ซึ่ง Lighthouse ได้แนะนำ 2 โอกาสในการตรวจสอบไว้ด้วย ซึ่งได้แก่ กำจัดทรัพยากรที่บล็อกการแสดงผลและเชื่อมต่อกับต้นทางที่จำเป็นล่วงหน้า (แม้ว่าเมตริกทั้งหมดเป็นสีเขียว แต่การเพิ่มประสิทธิภาพจะยังคงให้ผลที่ดีขึ้น)
![ภาพหน้าจอของการตรวจสอบ Lighthouse ที่แสดง FCP 2.4 วินาทีและโอกาส 2 รายการ: กำจัดทรัพยากรที่บล็อกการแสดงผลและเชื่อมต่อล่วงหน้ากับต้นทางที่จำเป็น](https://web.dev/static/articles/codelab-optimize-third-party-javascript/image/screenshot-lighthouse-au-d025b777206eb.png?authuser=5&hl=th)
เลื่อน JavaScript ของบุคคลที่สาม
การตรวจสอบกำจัดทรัพยากรที่บล็อกการแสดงผลระบุว่าคุณสามารถประหยัดเวลาได้โดยการเลื่อนสคริปต์ที่มาจาก d3js.org ดังนี้
![ภาพหน้าจอของการตรวจสอบทรัพยากรที่บล็อกการแสดงผลโดยไฮไลต์สคริปต์ d3.v3.min.js](https://web.dev/static/articles/codelab-optimize-third-party-javascript/image/screenshot-eliminate-ren-e12e8b7ae1ab3.png?authuser=5&hl=th)
D3.js เป็นไลบรารี JavaScript สำหรับสร้างการแสดงภาพข้อมูล ไฟล์ script.js
ในแอปตัวอย่างใช้ฟังก์ชันยูทิลิตี D3 เพื่อสร้างแผนภูมิเส้น SVG แล้วนำไปต่อท้ายหน้าเว็บ ลำดับการดำเนินการในที่นี้มีความสำคัญ: script.js
ต้องทำงานหลังจากแยกวิเคราะห์เอกสารและโหลดไลบรารี D3 แล้ว ไฟล์ดังกล่าวจึงถูกรวมไว้ด้านหน้าแท็กปิด </body>
ใน index.html
แต่สคริปต์ D3 จะรวมอยู่ใน <head>
ของหน้าเว็บ ซึ่งบล็อกการแยกวิเคราะห์ของเอกสารที่เหลือ:
![ภาพหน้าจอของ index.html พร้อมแท็กสคริปต์ที่ไฮไลต์อยู่ในส่วนหัว](https://web.dev/static/articles/codelab-optimize-third-party-javascript/image/screenshot-indexhtml-h-4a8c4790995c8.png?authuser=5&hl=th)
แอตทริบิวต์เวทมนตร์ 2 อย่างสามารถเลิกบล็อกโปรแกรมแยกวิเคราะห์ได้เมื่อเพิ่มลงในแท็กสคริปต์ ดังนี้
async
จะช่วยให้สคริปต์ดาวน์โหลดอยู่ในเบื้องหลังและทํางานในโอกาสแรกหลังจากที่ดาวน์โหลดเสร็จแล้วdefer
ช่วยให้มั่นใจได้ว่าสคริปต์จะดาวน์โหลดในเบื้องหลังและเรียกใช้หลังจากการแยกวิเคราะห์เสร็จสมบูรณ์
เนื่องจากแผนภูมินี้ไม่ได้มีความสำคัญต่อหน้าเว็บโดยรวมอย่างมากและมีแนวโน้มที่จะอยู่ครึ่งหน้าล่าง ให้ใช้ defer
เพื่อให้แน่ใจว่าไม่มีการบล็อกโปรแกรมแยกวิเคราะห์
ขั้นตอนที่ 1: โหลดสคริปต์แบบไม่พร้อมกันด้วยแอตทริบิวต์ defer
ในบรรทัดที่ 17 ของ index.html
ให้เพิ่มแอตทริบิวต์ defer
ลงในองค์ประกอบ <script>
ดังนี้
<script src="https://d3js.org/d3.v3.min.js" defer></script>
ขั้นตอนที่ 2: ตรวจสอบว่าลำดับการดำเนินการถูกต้อง
ตอนนี้เมื่อมีการเลื่อนเวลา D3 script.js
จะทำงานก่อนที่ D3 จะพร้อมทำงาน ซึ่งส่งผลให้เกิดข้อผิดพลาด
สคริปต์ที่มีแอตทริบิวต์ defer
จะทำงานตามลำดับที่ระบุไว้ หากต้องการให้ script.js
ทำงานหลังจาก D3 พร้อมใช้งานแล้ว ให้เพิ่ม defer
ลงในไฟล์และย้ายไปไว้ใน <head>
ของเอกสาร โดยให้อยู่หลังองค์ประกอบ D3 <script>
ตอนนี้จะไม่มีการบล็อกโปรแกรมแยกวิเคราะห์อีกต่อไป และการดาวน์โหลดจะเริ่มเร็วขึ้น
<script src="https://d3js.org/d3.v3.min.js" defer></script>
<script src="./script.js" defer></script>
ทรัพยากรของบุคคลที่สามแบบ Lazy Loading
ทรัพยากรทั้งหมดที่อยู่ครึ่งหน้าล่างเป็นตัวเลือกที่ดีสำหรับการโหลดแบบ Lazy Loading
แอปตัวอย่างมีวิดีโอ YouTube ฝังอยู่ใน iframe หากต้องการดูจำนวนคำขอที่หน้าเว็บสร้างและคำขอมาจาก iframe ของ YouTube ที่ฝังไว้ ให้ทำดังนี้
- หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ
- กด "Control+Shift+J" (หรือ "Command+Option+J" ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาเว็บ
- คลิกแท็บเครือข่าย
- เลือกช่องทำเครื่องหมายปิดใช้แคช
- เลือก Fast 3G ในเมนูแบบเลื่อนลงการควบคุม
- โหลดหน้าเว็บซ้ำ
แผงเครือข่ายจะแสดงว่าหน้าเว็บส่งคำขอทั้งหมด 28 รายการและโอนทรัพยากรที่บีบอัดไว้เกือบ 1 MB
หากต้องการระบุคำขอที่ iframe
ของ YouTube สร้างขึ้น ให้มองหารหัสวิดีโอ 6lfaiXM6waw
ในคอลัมน์ Initiator หากต้องการจัดกลุ่มคำขอทั้งหมดตามโดเมน ให้ทำดังนี้
ในแผงเครือข่าย ให้คลิกขวาที่ชื่อคอลัมน์
เลือกคอลัมน์โดเมนในเมนูแบบเลื่อนลง
หากต้องการจัดเรียงคำขอตามโดเมน ให้คลิกชื่อคอลัมน์โดเมน
การจัดเรียงใหม่เผยให้เห็นว่ามีคำขอเพิ่มเติมที่ส่งไปยัง Google Domains โดยรวมแล้ว iframe ของ YouTube สร้างคำขอสคริปต์ สไตล์ชีต รูปภาพ และแบบอักษร 14 รายการ แต่หากผู้ใช้ไม่ได้เลื่อนลงเพื่อเล่นวิดีโอจริงๆ พวกเขาก็ไม่จำเป็นต้องใช้เนื้อหาเหล่านั้นทั้งหมด
การรอให้วิดีโอโหลดแบบ Lazy Loading จนกว่าผู้ใช้จะเลื่อนลงไปที่ส่วนดังกล่าวของหน้า จะเป็นการลดจำนวนคำขอที่หน้าเว็บสร้างขึ้นในตอนแรก วิธีนี้จะบันทึกข้อมูลของผู้ใช้และเร่งการโหลดเริ่มต้นให้เร็วขึ้น
วิธีหนึ่งในการใช้งานการโหลดแบบ Lazy Loading คือการใช้ Intersection Observer ซึ่งเป็น API ของเบราว์เซอร์ที่แจ้งให้คุณทราบเมื่อมีองค์ประกอบเข้าหรือออกจากวิวพอร์ตของเบราว์เซอร์
ขั้นตอนที่ 1: ป้องกันไม่ให้วิดีโอโหลดในตอนแรก
หากต้องการโหลด iframe ของวิดีโอแบบ Lazy Loading คุณต้องป้องกันไม่ให้ URL โหลดด้วยวิธีปกติก่อน โดยแทนที่แอตทริบิวต์ src
ด้วยแอตทริบิวต์ data-src
เพื่อระบุ URL ของวิดีโอ ดังนี้
<iframe width="560" height="315" data-src="https://www.youtube.com/embed/lS9D6w1GzGY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
data-src
คือแอตทริบิวต์ข้อมูล ซึ่งช่วยให้คุณจัดเก็บข้อมูลเพิ่มเติมเกี่ยวกับองค์ประกอบ HTML มาตรฐานได้ คุณจะตั้งชื่อแอตทริบิวต์ข้อมูลเป็นอะไรก็ได้ตราบใดที่แอตทริบิวต์ขึ้นต้นด้วย "data-"
iframe ที่ไม่มี src
จะไม่โหลด
ขั้นตอนที่ 2: ใช้ Intersection Observer เพื่อโหลดวิดีโอแบบ Lazy Loading
หากต้องการโหลดวิดีโอเมื่อผู้ใช้เลื่อนดูวิดีโอ คุณจำเป็นต้องทราบเมื่อปรากฏขึ้น และนั่นคือจุดที่ Intersection Observer API เข้ามา Intersection Observer API ช่วยให้คุณสามารถลงทะเบียนฟังก์ชันเรียกกลับที่จะทำงานทุกครั้งที่องค์ประกอบที่คุณต้องการติดตามเข้าหรือออกจากวิวพอร์ต
หากต้องการเริ่มต้นใช้งาน ให้สร้างไฟล์ใหม่และตั้งชื่อว่า lazy-load.js
:
- คลิกไฟล์ใหม่ แล้วตั้งชื่อ
- คลิกเพิ่มไฟล์นี้
เพิ่มแท็กสคริปต์ลงในส่วนหัวของเอกสารดังนี้
<script src="/lazy-load.js" defer></script>
ใน lazy-load.js
ให้สร้าง IntersectionObserver
ใหม่และส่งฟังก์ชันเรียกกลับให้เรียกใช้
// create a new Intersection Observer
let observer = new IntersectionObserver(callback);
ตอนนี้ให้กำหนดองค์ประกอบเป้าหมายให้ observer
เพื่อรับชม (ในกรณีนี้คือ iframe วิดีโอ) โดยส่งผ่านค่าเป็นอาร์กิวเมนต์ในเมธอด observe
ดังนี้
// the element that you want to watch
const element = document.querySelector('iframe');
// register the element with the observe method
observer.observe(element);
callback
จะได้รับรายการออบเจ็กต์ IntersectionObserverEntry
และออบเจ็กต์ IntersectionObserver
เอง แต่ละรายการจะมีองค์ประกอบ target
และพร็อพเพอร์ตี้ที่อธิบายขนาด ตำแหน่ง เวลาที่อุปกรณ์เข้าสู่วิวพอร์ต และอื่นๆ หนึ่งในพร็อพเพอร์ตี้ของ IntersectionObserverEntry
คือ isIntersecting
ซึ่งเป็นค่าบูลีนที่เท่ากับ true
เมื่อองค์ประกอบเข้าสู่วิวพอร์ต
ในตัวอย่างนี้ target
คือ iframe
isIntersecting
เท่ากับ true
เมื่อ target
เข้าสู่วิวพอร์ต หากต้องการดูการทำงานจริง ให้แทนที่ callback
ด้วยฟังก์ชันต่อไปนี้
let observer = new IntersectionObserver(callback);
let observer = new IntersectionObserver(function(entries, observer) {
entries.forEach(entry => {
console.log(entry.target);
console.log(entry.isIntersecting);
});
});
- หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ
- กด "Control+Shift+J" (หรือ "Command+Option+J" ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาเว็บ
- คลิกแท็บคอนโซล
ลองเลื่อนขึ้นและลง คุณควรจะเห็นค่าการเปลี่ยนแปลง isIntersecting
และองค์ประกอบเป้าหมายบันทึกไปยังคอนโซลแล้ว
หากต้องการโหลดวิดีโอเมื่อผู้ใช้เลื่อนไปยังตำแหน่งของวิดีโอ ให้ใช้ isIntersecting
เป็นเงื่อนไขเพื่อเรียกใช้ฟังก์ชัน loadElement
ซึ่งจะรับค่าจาก data-src
ขององค์ประกอบ iframe
และตั้งค่าเป็นแอตทริบิวต์ src
ขององค์ประกอบ iframe
การแทนที่ดังกล่าวจะทำให้มีการโหลดวิดีโอ จากนั้นเมื่อวิดีโอโหลดแล้ว ให้เรียกใช้เมธอด unobserve
ใน observer
เพื่อหยุดการดูองค์ประกอบเป้าหมาย ดังนี้
let observer = new IntersectionObserver(function (entries, observer) {
entries.forEach(entry => {
console.log(entry.target);
console.log(entry.isIntersecting);
});
});
if (entry.isIntersecting) {
// do this when the element enters the viewport
loadElement(entry.target);
// stop watching
observer.unobserve(entry.target);
}
});
});
function loadElement(element) {
const src = element.getAttribute('data-src');
element.src = src;
}
ขั้นตอนที่ 3: ประเมินประสิทธิภาพอีกครั้ง
หากต้องการดูว่าขนาดและจำนวนทรัพยากรเปลี่ยนไปอย่างไร ให้เปิดแผงเครือข่ายเครื่องมือสำหรับนักพัฒนาเว็บ แล้วโหลดหน้าเว็บอีกครั้ง แผงเครือข่ายจะแสดงว่าหน้าเว็บนั้นส่งคำขอ 14 รายการและมีขนาดเพียง 260 KB เป็นการปรับปรุงที่สำคัญ
ตอนนี้ให้เลื่อนลงไปที่ด้านล่างของหน้าและคอยสังเกตแผงเครือข่าย เมื่อมาถึงวิดีโอ คุณควรจะเห็นหน้าเว็บกระตุ้นคำขอเพิ่มเติม
เชื่อมต่อกับต้นทางที่จำเป็นล่วงหน้า
คุณได้เลื่อนเวลา JavaScript ที่ไม่สำคัญและโหลดคำขอ YouTube แบบ Lazy Loading ดังนั้น ตอนนี้ก็ถึงเวลาเพิ่มประสิทธิภาพเนื้อหาของบุคคลที่สามที่เหลืออยู่
การเพิ่มแอตทริบิวต์ rel=preconnect
ลงในลิงก์จะบอกให้เบราว์เซอร์สร้างการเชื่อมต่อกับโดเมนก่อนที่จะส่งคำขอสำหรับทรัพยากรนั้น แอตทริบิวต์นี้จะใช้ได้ดีที่สุดในต้นทางซึ่งมีทรัพยากรที่คุณแน่ใจว่าต้องการหน้าเว็บ
การตรวจสอบ Lighthouse ที่คุณดำเนินการในขั้นตอนแรกซึ่งแนะนำในเชื่อมต่อกับต้นทางที่จำเป็นล่วงหน้า ซึ่งคุณประหยัดเวลาได้ประมาณ 400 มิลลิวินาทีด้วยการสร้างการเชื่อมต่อก่อนเปิดตัวไปยัง staticxx.facebook.com และ youtube.com โดยทำดังนี้
เนื่องจากวิดีโอ YouTube ในตอนนี้เป็นการโหลดแบบ Lazy Loading จึงเหลือเพียง staticxx.facebook.com ซึ่งเป็นแหล่งที่มาของวิดเจ็ตการแชร์ในโซเชียลมีเดีย เริ่มต้นการเชื่อมต่อโดเมนนี้ได้ง่ายๆ ด้วยการเพิ่มแท็ก <link>
ลงใน <head>
ของเอกสาร:
<link rel="preconnect" href="https://staticxx.facebook.com">
ประเมินประสิทธิภาพอีกครั้ง
นี่คือสถานะของหน้าเว็บหลังจากการเพิ่มประสิทธิภาพ ทำตามขั้นตอนจากส่วนวัดประสิทธิภาพของ Codelab เพื่อเรียกใช้การตรวจสอบ Lighthouse อีกรายการหนึ่ง