ลดเพย์โหลด JavaScript ด้วยการแยกโค้ด

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

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

หน้าต่างเบราว์เซอร์แสดงแอปพลิเคชันชื่อ Magic Sorter ซึ่งมีช่องสำหรับป้อนตัวเลข 3 ช่องและปุ่มจัดเรียง

วัดผล

เช่นเคย สิ่งสำคัญคือต้องวัดประสิทธิภาพของเว็บไซต์ก่อนที่จะพยายามเพิ่มการเพิ่มประสิทธิภาพใดๆ

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

แผงเครือข่ายแสดงแพ็กเกจ JavaScript ขนาด 71.2 KB

JavaScript ขนาด 71.2 KB เพียงเพื่อจัดเรียงตัวเลขไม่กี่ตัวในแอปพลิเคชันง่ายๆ What gives?

ในซอร์สโค้ด (src/index.js) มีการนำเข้าและใช้ไลบรารี lodash ในแอปพลิเคชันนี้ Lodash มีฟังก์ชันยูทิลิตีที่มีประโยชน์มากมาย แต่ที่นี่ใช้เพียงเมธอดเดียวจากแพ็กเกจ การติดตั้งและนำเข้าการขึ้นต่อกันทั้งหมดของบุคคลที่สามในกรณีที่ใช้เพียงบางส่วน เป็นข้อผิดพลาดที่พบบ่อย

เพิ่มประสิทธิภาพ

การลดขนาดแพ็กเกจทำได้ 2-3 วิธีดังนี้

  1. เขียนวิธีการจัดเรียงที่กำหนดเองแทนการนำเข้าไลบรารีของบุคคลที่สาม
  2. ใช้วิธี Array.prototype.sort() ในตัวเพื่อจัดเรียงตามตัวเลข
  3. นำเข้าเฉพาะเมธอด sortBy จาก lodash เท่านั้น ไม่ใช่นำเข้าทั้งไลบรารี
  4. ดาวน์โหลดโค้ดสำหรับการจัดเรียงเมื่อผู้ใช้คลิกปุ่มเท่านั้น

ตัวเลือกที่ 1 และ 2 เป็นวิธีที่เหมาะสมอย่างยิ่งในการลดขนาดแพ็กเกจ (และน่าจะเป็นวิธีที่สมเหตุสมผลที่สุดสำหรับแอปพลิเคชันจริง) อย่างไรก็ตาม เราจะไม่ใช้ในบทแนะนำนี้เพื่อวัตถุประสงค์ในการสอน 😈

ทั้งตัวเลือกที่ 3 และ 4 จะช่วยปรับปรุงประสิทธิภาพของแอปพลิเคชันนี้ ส่วนถัดไปของโค้ดแล็บนี้จะครอบคลุมขั้นตอนเหล่านี้ เช่นเดียวกับบทแนะนำการเขียนโค้ด อื่นๆ ให้ลองเขียนโค้ดด้วยตนเองเสมอแทนการคัดลอกและวาง

นำเข้าเฉพาะสิ่งที่ต้องการ

คุณต้องแก้ไขไฟล์บางไฟล์เพื่อนำเข้าเฉพาะวิธีการเดียวจาก lodash ก่อนอื่น ให้แทนที่การอ้างอิงนี้ใน package.json

"lodash": "^4.7.0",

ด้วยสิ่งต่อไปนี้

"lodash.sortby": "^4.7.0",

ตอนนี้ใน src/index.js ให้นำเข้าโมดูลนี้โดยเฉพาะ

import "./style.css";
import _ from "lodash";
import sortBy from "lodash.sortby";

และอัปเดตวิธีจัดเรียงค่าดังนี้

form.addEventListener("submit", e => {
  e.preventDefault();
  const values = [input1.valueAsNumber, input2.valueAsNumber, input3.valueAsNumber];
  const sortedValues = _.sortBy(values);
  const sortedValues = sortBy(values);

  results.innerHTML = `
    <h2>
      ${sortedValues}
    </h2>
  `
});

โหลดแอปพลิเคชันซ้ำ เปิดเครื่องมือสำหรับนักพัฒนาเว็บ แล้วดูแผงเครือข่ายอีกครั้ง

แผงเครือข่ายแสดง JavaScript Bundle ขนาด 15.2 KB

สําหรับแอปพลิเคชันนี้ เราลดขนาด Bundle ได้มากกว่า 4 เท่าโดยใช้ความพยายามเพียงเล็กน้อย แต่ก็ยังมีโอกาสปรับปรุงได้อีก

การแยกโค้ด

webpack เป็นหนึ่งในเครื่องมือจัดกลุ่มโมดูลโอเพนซอร์สที่ได้รับความนิยมมากที่สุดในปัจจุบัน กล่าวโดยย่อคือ Bundler จะรวมโมดูล JavaScript ทั้งหมด (รวมถึงชิ้นงานอื่นๆ) ที่ประกอบกันเป็นเว็บแอปพลิเคชันไว้ในไฟล์แบบคงที่ที่เบราว์เซอร์อ่านได้

แพ็กเกจเดียวที่ใช้ในแอปพลิเคชันนี้สามารถแบ่งออกเป็น 2 ก้อนแยกกันได้ดังนี้

  • หนึ่งคือผู้รับผิดชอบโค้ดที่ประกอบกันเป็นเส้นทางเริ่มต้นของเรา
  • ก้อนข้อมูลรองที่มีโค้ดการจัดเรียง

การใช้การนำเข้าแบบไดนามิกช่วยให้โหลดแบบ Lazy Loading หรือ โหลดตามต้องการได้ ในแอปพลิเคชันนี้ ระบบจะโหลดโค้ดที่ประกอบกันเป็นก้อนได้ก็ต่อเมื่อผู้ใช้กดปุ่มเท่านั้น

เริ่มด้วยการนำการนำเข้าระดับบนสุดสำหรับเมธอดการจัดเรียงใน src/index.js ออก

import sortBy from "lodash.sortby";

และนำเข้าภายใน Listener เหตุการณ์ที่เริ่มทำงานเมื่อกดปุ่ม

form.addEventListener("submit", e => {
  e.preventDefault();
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

ฟีเจอร์ import() เป็นส่วนหนึ่งของข้อเสนอ (ปัจจุบันอยู่ในขั้นตอนที่ 3 ของกระบวนการ TC39) เพื่อรวมความสามารถในการนำเข้าโมดูลแบบไดนามิก webpack ได้รวมการรองรับฟีเจอร์นี้ไว้แล้วและใช้ไวยากรณ์เดียวกันกับที่ระบุไว้ในข้อเสนอ

import() จะแสดงผล Promise และเมื่อ Promise แก้ไขแล้ว ระบบจะแสดงโมดูลที่เลือก ซึ่งแยกออกเป็นก้อนแยกต่างหาก หลังจากส่งคืนโมดูลแล้ว module.default จะใช้เพื่ออ้างอิงการส่งออกเริ่มต้นที่ lodash จัดเตรียมไว้ โดยจะมีการเชื่อมโยง Promise กับ .then อีกรายการหนึ่งซึ่ง เรียกใช้เมธอด sortInput เพื่อจัดเรียงค่าอินพุตทั้ง 3 ค่า ที่ส่วนท้ายของ Promise Chain .catch() ใช้เพื่อจัดการกรณีที่สัญญาถูกปฏิเสธ เนื่องจากข้อผิดพลาด

สิ่งสุดท้ายที่ต้องทำคือเขียนเมธอด sortInput ที่ส่วนท้ายของไฟล์ โดยต้องเป็นฟังก์ชันที่แสดงผลฟังก์ชันที่ รับเมธอดที่นำเข้าจาก lodash.sortBy จากนั้นฟังก์ชันที่ซ้อนกันจะ จัดเรียงค่าอินพุตทั้ง 3 ค่าและอัปเดต DOM

const sortInput = () => {
  return (sortBy) => {
    const values = [
      input1.valueAsNumber,
      input2.valueAsNumber,
      input3.valueAsNumber
    ];
    const sortedValues = sortBy(values);

    results.innerHTML = `
      <h2>
        ${sortedValues}
      </h2>
    `
  };
}

ตรวจสอบ

โหลดแอปพลิเคชันซ้ำอีกครั้งและจับตาดูแผงเครือข่าย อีกครั้ง ระบบจะดาวน์โหลดเฉพาะ Bundle เริ่มต้นขนาดเล็กทันทีที่แอป โหลด

แผงเครือข่ายแสดงแพ็กเกจ JavaScript ขนาด 2.7 KB

หลังจากกดปุ่มเพื่อจัดเรียงตัวเลขที่ป้อน ระบบจะดึงข้อมูลและเรียกใช้ก้อนข้อมูลที่มีโค้ดการจัดเรียง

แผงเครือข่ายแสดง JavaScript Bundle ขนาด 2.7 KB ตามด้วย JavaScript Bundle ขนาด 13.9 KB

สังเกตว่าระบบยังคงจัดเรียงตัวเลข

บทสรุป

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

UI การโหลดแบบ Lazy Loading

เมื่อโหลดโค้ดบางโมดูลแบบ Lazy Loading คุณควรพิจารณาว่าผู้ใช้ที่มีการเชื่อมต่อเครือข่ายไม่เสถียรจะได้รับ ประสบการณ์การใช้งานอย่างไร การแยกและ โหลดโค้ดจำนวนมากเมื่อผู้ใช้ส่งการดำเนินการอาจทำให้ดูเหมือนว่าแอปพลิเคชันหยุดทำงาน ดังนั้นให้พิจารณาแสดง ตัวบ่งชี้การโหลดบางอย่าง

การโหลดโมดูลโหนดของบุคคลที่สามแบบ Lazy Loading

การโหลดทรัพยากร Dependency ของบุคคลที่สามแบบเลซี่ในแอปพลิเคชันอาจไม่ใช่แนวทางที่ดีที่สุดเสมอไป และขึ้นอยู่กับว่าคุณใช้ทรัพยากรเหล่านั้นที่ใด โดยปกติแล้ว ระบบจะแยกการขึ้นต่อกับบุคคลที่สาม ออกเป็นvendorแพ็กเกจแยกต่างหากที่แคชได้เนื่องจาก ไม่ได้อัปเดตบ่อยนัก อ่านเพิ่มเติมเกี่ยวกับวิธีที่ SplitChunksPlugin ช่วยคุณทำสิ่งนี้ได้

การโหลดเมื่อจำเป็นด้วยเฟรมเวิร์ก JavaScript

เฟรมเวิร์กและไลบรารียอดนิยมหลายรายการที่ใช้ webpack มีการแยกส่วนเพื่อ ทำให้การโหลดแบบ Lazy ง่ายกว่าการใช้การนำเข้าแบบไดนามิกในส่วนกลางของ แอปพลิเคชัน

แม้ว่าการทำความเข้าใจวิธีการทำงานของการนำเข้าแบบไดนามิกจะมีประโยชน์ แต่ให้ใช้วิธีที่เฟรมเวิร์ก/ไลบรารีแนะนำเสมอเพื่อโหลดโมดูลที่เฉพาะเจาะจงแบบ Lazy Load

การโหลดล่วงหน้าและการดึงข้อมูลล่วงหน้า

หากเป็นไปได้ ให้ใช้ประโยชน์จากคำแนะนำของเบราว์เซอร์ เช่น <link rel="preload"> หรือ <link rel="prefetch"> เพื่อลองโหลดโมดูลที่สำคัญให้เร็วขึ้น webpack รองรับคำแนะนำทั้ง 2 รายการผ่านการใช้ความคิดเห็นแบบพิเศษในคำสั่งนำเข้า ซึ่งอธิบายไว้อย่างละเอียดในคู่มือโหลดล่วงหน้าสำหรับก้อนข้อมูลที่สำคัญ

การโหลดแบบ Lazy Loading มากกว่าโค้ด

รูปภาพอาจเป็นส่วนสำคัญของแอปพลิเคชัน การโหลดแบบ Lazy Loading สำหรับรูปภาพที่อยู่ ใต้พับหน้าเว็บหรืออยู่นอกวิวพอร์ตของอุปกรณ์จะช่วยเพิ่มความเร็วของเว็บไซต์ได้ อ่านข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ในคู่มือ Lazysizes