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

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

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

คุณตัดขนาดแพ็กเกจได้ 2-3 วิธีดังนี้

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

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

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

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

ต้องแก้ไขไฟล์ 2-3 ไฟล์เพื่อนำเข้าวิธีเดียวเท่านั้นจาก 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

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

ตรวจสอบ

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

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

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

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

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

บทสรุป

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

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

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

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

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

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

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

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

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

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

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

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