ลดเพย์โหลด 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 เพียงเพื่อจัดเรียงตัวเลข 2-3 ตัวในแอปพลิเคชันง่ายๆ What gives?

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

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

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

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

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

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

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

คุณต้องแก้ไขไฟล์ 2-3 ไฟล์เพื่อนําเข้าเฉพาะวิธีการเดียวจาก 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 ขนาด 15.2 KB

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

การแยกโค้ด

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

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

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

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

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

ติดตามดู

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

แผงเครือข่ายแสดงกลุ่ม JavaScript ขนาด 2.7 KB

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

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

โปรดสังเกตว่าตัวเลขยังคงจัดเรียงอยู่

บทสรุป

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

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

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

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

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

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

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

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

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

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

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

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