เพิ่มประสิทธิภาพ JavaScript ของบุคคลที่สาม

สคริปต์ของบุคคลที่สามส่งผลกระทบต่อประสิทธิภาพ คุณจึงต้องตรวจสอบสคริปต์ดังกล่าวเป็นประจำและใช้เทคนิคที่มีประสิทธิภาพในการโหลด Codelab นี้แสดงวิธีเพิ่มประสิทธิภาพการโหลดทรัพยากรของบุคคลที่สาม โดยจะอธิบายเทคนิคต่อไปนี้

  • กำลังเลื่อนการโหลดสคริปต์

  • การโหลดแบบ Lazy Loading ทรัพยากรที่ไม่สำคัญ

  • เชื่อมต่อกับต้นทางที่จำเป็นล่วงหน้า

แอปตัวอย่างที่รวมไว้นำเสนอหน้าเว็บที่เรียบง่ายพร้อมด้วยฟีเจอร์ 3 อย่างที่มาจากแหล่งข้อมูลของบุคคลที่สาม ดังนี้

  • วิดีโอที่ฝัง

  • ไลบรารีการแสดงข้อมูลผ่านภาพสำหรับแสดงผลกราฟเส้น

  • วิดเจ็ตการแชร์ผ่านโซเชียลมีเดีย

ภาพหน้าจอของหน้าเว็บที่ไฮไลต์ทรัพยากรของบุคคลที่สาม
ทรัพยากรของบุคคลที่สามในแอปตัวอย่าง

คุณจะเริ่มต้นด้วยการวัดประสิทธิภาพของแอป จากนั้นจึงใช้เทคนิคแต่ละเทคนิคเพื่อปรับปรุงประสิทธิภาพของแอปในด้านต่างๆ

วัดประสิทธิภาพ

ก่อนอื่นให้เปิดแอปตัวอย่างในมุมมองแบบเต็มหน้าจอ โดยทำดังนี้

  1. คลิกรีมิกซ์เพื่อแก้ไขเพื่อทำให้โปรเจ็กต์แก้ไขได้
  2. หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ เต็มหน้าจอ

เรียกใช้การตรวจสอบประสิทธิภาพของ Lighthouse ในหน้าเว็บเพื่อสร้างประสิทธิภาพพื้นฐาน ดังนี้

  1. กด "Control+Shift+J" (หรือ "Command+Option+J" ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาเว็บ
  2. คลิกแท็บ Lighthouse
  3. คลิกอุปกรณ์เคลื่อนที่
  4. เลือกช่องทำเครื่องหมายประสิทธิภาพ (คุณสามารถล้างช่องทำเครื่องหมายที่เหลือได้ในส่วนการตรวจสอบ)
  5. คลิก 3G แบบรวดเร็วจำลอง, ความเร็ว CPU ช้าลง 4 เท่า
  6. เลือกช่องทำเครื่องหมายล้างพื้นที่เก็บข้อมูล
  7. คลิกดำเนินการตรวจสอบ

เมื่อทำการตรวจสอบบนเครื่อง ผลลัพธ์ที่แน่นอนอาจแตกต่างกันไป แต่คุณควรสังเกตเห็นว่าเวลา First Contentful Paint (FCP) ค่อนข้างสูง ซึ่ง Lighthouse ได้แนะนำ 2 โอกาสในการตรวจสอบไว้ด้วย ซึ่งได้แก่ กำจัดทรัพยากรที่บล็อกการแสดงผลและเชื่อมต่อกับต้นทางที่จำเป็นล่วงหน้า (แม้ว่าเมตริกทั้งหมดเป็นสีเขียว แต่การเพิ่มประสิทธิภาพจะยังคงให้ผลที่ดีขึ้น)

ภาพหน้าจอของการตรวจสอบ Lighthouse ที่แสดง FCP 2.4 วินาทีและโอกาส 2 รายการ: กำจัดทรัพยากรที่บล็อกการแสดงผลและเชื่อมต่อล่วงหน้ากับต้นทางที่จำเป็น

เลื่อน JavaScript ของบุคคลที่สาม

การตรวจสอบกำจัดทรัพยากรที่บล็อกการแสดงผลระบุว่าคุณสามารถประหยัดเวลาได้โดยการเลื่อนสคริปต์ที่มาจาก d3js.org ดังนี้

ภาพหน้าจอของการตรวจสอบทรัพยากรที่บล็อกการแสดงผลโดยไฮไลต์สคริปต์ d3.v3.min.js

D3.js เป็นไลบรารี JavaScript สำหรับสร้างการแสดงภาพข้อมูล ไฟล์ script.js ในแอปตัวอย่างใช้ฟังก์ชันยูทิลิตี D3 เพื่อสร้างแผนภูมิเส้น SVG แล้วนำไปต่อท้ายหน้าเว็บ ลำดับการดำเนินการในที่นี้มีความสำคัญ: script.js ต้องทำงานหลังจากแยกวิเคราะห์เอกสารและโหลดไลบรารี D3 แล้ว ไฟล์ดังกล่าวจึงถูกรวมไว้ด้านหน้าแท็กปิด </body> ใน index.html

แต่สคริปต์ D3 จะรวมอยู่ใน <head> ของหน้าเว็บ ซึ่งบล็อกการแยกวิเคราะห์ของเอกสารที่เหลือ:

ภาพหน้าจอของ index.html พร้อมแท็กสคริปต์ที่ไฮไลต์อยู่ในส่วนหัว

แอตทริบิวต์เวทมนตร์ 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 ที่ฝังไว้ ให้ทำดังนี้

  1. หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ เต็มหน้าจอ
  2. กด "Control+Shift+J" (หรือ "Command+Option+J" ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาเว็บ
  3. คลิกแท็บเครือข่าย
  4. เลือกช่องทำเครื่องหมายปิดใช้แคช
  5. เลือก Fast 3G ในเมนูแบบเลื่อนลงการควบคุม
  6. โหลดหน้าเว็บซ้ำ

ภาพหน้าจอของแผงเครือข่ายเครื่องมือสำหรับนักพัฒนาเว็บ

แผงเครือข่ายจะแสดงว่าหน้าเว็บส่งคำขอทั้งหมด 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);
    });
  });
  1. หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ เต็มหน้าจอ
  2. กด "Control+Shift+J" (หรือ "Command+Option+J" ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาเว็บ
  3. คลิกแท็บคอนโซล

ลองเลื่อนขึ้นและลง คุณควรจะเห็นค่าการเปลี่ยนแปลง 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 โดยทำดังนี้

เชื่อมต่อกับการตรวจสอบต้นทางที่จำเป็นล่วงหน้าที่ไฮไลต์โดเมน staticxx.facebook.com

เนื่องจากวิดีโอ YouTube ในตอนนี้เป็นการโหลดแบบ Lazy Loading จึงเหลือเพียง staticxx.facebook.com ซึ่งเป็นแหล่งที่มาของวิดเจ็ตการแชร์ในโซเชียลมีเดีย เริ่มต้นการเชื่อมต่อโดเมนนี้ได้ง่ายๆ ด้วยการเพิ่มแท็ก <link> ลงใน <head> ของเอกสาร:

  <link rel="preconnect" href="https://staticxx.facebook.com">

ประเมินประสิทธิภาพอีกครั้ง

นี่คือสถานะของหน้าเว็บหลังจากการเพิ่มประสิทธิภาพ ทำตามขั้นตอนจากส่วนวัดประสิทธิภาพของ Codelab เพื่อเรียกใช้การตรวจสอบ Lighthouse อีกรายการหนึ่ง

การตรวจสอบ Lighthouse ที่แสดง FCP 1 วินาทีและคะแนนประสิทธิภาพคือ 99