สคริปต์ของบุคคลที่สามส่งผลต่อประสิทธิภาพ คุณจึงควรตรวจสอบสคริปต์เป็นประจำและใช้เทคนิคที่มีประสิทธิภาพในการโหลด Codelab นี้จะแสดงวิธีเพิ่มประสิทธิภาพการโหลดทรัพยากรของบุคคลที่สาม โดยครอบคลุมถึงเทคนิคต่อไปนี้
เลื่อนการโหลดสคริปต์
การโหลดแบบ Lazy Loading ทรัพยากรที่ไม่สำคัญ
เชื่อมต่อกับต้นทางที่จำเป็นล่วงหน้า
แอปตัวอย่างที่รวมไว้มีหน้าเว็บง่ายๆ พร้อมฟีเจอร์ 3 รายการที่มาจากแหล่งข้อมูลของบุคคลที่สาม ได้แก่
การฝังวิดีโอ
ไลบรารีการแสดงข้อมูลผ่านภาพสำหรับการแสดงผลกราฟเส้น
วิดเจ็ตการแชร์โซเชียลมีเดีย
![ภาพหน้าจอของหน้าเว็บซึ่งไฮไลต์ทรัพยากรของบุคคลที่สาม](https://web.dev/static/articles/codelab-optimize-third-party-javascript/image/screenshot-the-page-thi-cc10c15b4c9aa.png?authuser=2&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=2&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=2&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=2&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
จะทำงานตามลำดับที่ระบุไว้ เพิ่ม defer
ลงในไฟล์และย้ายไปยัง <head>
ของเอกสาร โดยอยู่หลังองค์ประกอบ <script>
D3 เพื่อให้มั่นใจว่า script.js
จะทำงานหลังจาก D3 พร้อมใช้งาน ตอนนี้โปรแกรมจะไม่บล็อกโปรแกรมแยกวิเคราะห์อีกต่อไปและการดาวน์โหลดก็จะเริ่มต้นขึ้นเร็วขึ้น
<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) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาเว็บ
- คลิกแท็บเครือข่าย
- เลือกช่องทำเครื่องหมายปิดใช้แคช
- เลือก 3G ที่รวดเร็วในเมนูแบบเลื่อนลงการควบคุม
- โหลดหน้าเว็บซ้ำ
แผงเครือข่ายจะแสดงว่าหน้าเว็บได้ส่งคำขอทั้งหมด 28 รายการและโอนทรัพยากรที่บีบอัดแล้วเกือบ 1 MB
หากต้องการระบุคำขอที่ iframe
ของ YouTube สร้างขึ้น ให้มองหารหัสวิดีโอ 6lfaiXM6waw
ในคอลัมน์ตัวเริ่มต้น หากต้องการจัดกลุ่มคำขอทั้งหมดตามโดเมน ให้ทำดังนี้
ในแผงเครือข่าย ให้คลิกขวาที่ชื่อคอลัมน์
เลือกคอลัมน์โดเมนในเมนูแบบเลื่อนลง
หากต้องการจัดเรียงคำขอตามโดเมน ให้คลิกชื่อคอลัมน์โดเมน
การจัดเรียงใหม่จะแสดงให้เห็นว่ามีคำขอเพิ่มเติมไปยัง Google Domains โดยรวมแล้ว iframe ของ YouTube จะสร้างคำขอ 14 รายการสำหรับสคริปต์ สไตล์ชีต รูปภาพ และแบบอักษร แต่หากผู้ใช้ไม่ได้เลื่อนลงเพื่อเล่นวิดีโอจริงๆ ผู้ใช้ก็ไม่ได้ต้องการเนื้อหาเหล่านั้นทั้งหมด
การที่รอโหลดวิดีโอแบบ Lazy Loading จนกว่าผู้ใช้จะเลื่อนลงไปที่ส่วนดังกล่าวของหน้า จะช่วยลดจำนวนคำขอที่หน้าเว็บสร้างขึ้นในตอนแรก วิธีนี้ช่วยให้ผู้ใช้ประหยัด ข้อมูลและช่วยให้โหลดครั้งแรกเร็วขึ้น
วิธีหนึ่งในการใช้การโหลดแบบ Lazy Loading คือการใช้ Intersection Observer ซึ่งเป็น API ของเบราว์เซอร์ที่แจ้งเตือนคุณเมื่อองค์ประกอบเข้าหรือออกจากวิวพอร์ตของเบราว์เซอร์
ขั้นตอนที่ 1: ป้องกันไม่ให้วิดีโอโหลดในตอนแรก
หากต้องการโหลดแบบ Lazy Loading ของ iframe ของวิดีโอ คุณต้องป้องกันไม่ให้โหลดตามปกติก่อน ซึ่งทำได้โดยแทนที่แอตทริบิวต์ 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 ให้คุณลงทะเบียนฟังก์ชัน Callback ซึ่งจะทำงานทุกครั้งที่องค์ประกอบที่คุณต้องการติดตามเข้าหรือออกจากวิวพอร์ต
หากต้องการเริ่มต้นใช้งาน ให้สร้างไฟล์ใหม่และตั้งชื่อว่า lazy-load.js
:
- คลิกไฟล์ใหม่ และตั้งชื่อ
- คลิก Add This File
เพิ่มแท็กสคริปต์ในส่วนหัวของเอกสารดังนี้
<script src="/lazy-load.js" defer></script>
ใน lazy-load.js
ให้สร้าง IntersectionObserver
ใหม่และส่งฟังก์ชัน Callback เพื่อเรียกใช้ดังต่อไปนี้
// 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 อีกครั้ง