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

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

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

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

วัดผล

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

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

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

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

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

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

คุณลดขนาดแพ็กเกจได้หลายวิธี ดังนี้

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

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

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

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

คุณต้องแก้ไขไฟล์บางไฟล์เพื่อนำเข้าเฉพาะเมธอดเดียวจาก lodash เริ่มต้นด้วยการแทนที่ทรัพยากร Dependency นี้ใน 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 ขนาด 15.2 KB

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

การแยกโค้ด

webpack เป็นหนึ่งในเครื่องมือรวมโมดูลแบบโอเพนซอร์สที่ได้รับความนิยมมากที่สุดในปัจจุบัน กล่าวโดยย่อคือ Webpack จะรวมโมดูล 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 และเมื่อแก้ไขแล้ว ระบบจะแสดงโมดูลที่เลือกซึ่งแยกออกเป็นกลุ่มแยกต่างหาก หลังจากโมดูลแสดงผลแล้ว ระบบจะใช้ module.default เพื่ออ้างอิงการส่งออกเริ่มต้นที่ lodash มีให้ Promise จะเชื่อมโยงกับ .then อื่นที่เรียกใช้เมธอด sortInput เพื่อจัดเรียงค่าอินพุต 3 ค่า ที่ส่วนท้ายของเชน Promisecatch() ใช้เพื่อจัดการกรณีที่สัญญาถูกปฏิเสธเนื่องจากข้อผิดพลาด

สิ่งสุดท้ายที่ต้องทำคือเขียนเมธอด 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>
    `
  };
}

ตรวจสอบ

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

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

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

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

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

บทสรุป

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

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

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

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

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

การโหลดแบบ Lazy Loading ด้วยเฟรมเวิร์ก JavaScript

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

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

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

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

การโหลดแบบ Lazy Loading ไม่ได้ใช้กับโค้ดเท่านั้น

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