Web Performance

ทำไมเว็บไซต์ของคุณควรส่งคำขอน้อยลง ไม่ใช่แค่ทำให้แต่ละคำขอเล็กลง

ไฟล์ขนาดจิ๋วไม่ได้ฟรี HTTP สมัยใหม่ทำให้ค่าใช้จ่ายของคำขอลดลง แต่ไม่ได้ทำให้หมดความสำคัญ

The Wux Webtools Team The Wux Webtools Team 23 อ่านขั้นต่ำ ช่วยโดย AI, ตรวจสอบโดยมนุษย์
A stylized browser waterfall showing many small requests simplified into fewer intentional requests.
สารบัญ
  1. มายาคติแสนสบายของ “แค่ทำให้ทุกไฟล์เล็กลง”
  2. คำขอไม่ใช่แค่จำนวนไบต์
  3. “แต่ HTTP/2 แก้เรื่องนี้แล้ว” ส่วนใหญ่ยังไม่ใช่
  4. Waterfall คือที่ที่ความจริงอยู่
  5. ไฟล์ที่เล็กลงยังสำคัญ — แค่ไม่สำคัญเท่ากันทั้งหมด
  6. ต้นทุนที่ซ่อนอยู่ของไฟล์เล็กจำนวนมาก
  7. 1. การค้นพบที่ล่าช้า
  8. 2. ค่าใช้จ่ายของ headers
  9. 3. การขัดจังหวะ main thread
  10. 4. ความซับซ้อนของ cache
  11. Bundling กลับมาแล้ว แต่ต้องใช้วิจารณญาณ
  12. คำขอจาก third-party ควรถูกสงสัยเป็นพิเศษ
  13. Checklist เชิงปฏิบัติสำหรับการลดคำขอ
  14. ลบ
  15. รวมอย่างรอบคอบ
  16. หน่วง
  17. Cache อย่างเหมาะสม
  18. วัดใหม่
  19. หน้าตาที่ดีเป็นอย่างไร

มายาคติแสนสบายของ “แค่ทำให้ทุกไฟล์เล็กลง”

เป็นเวลาหลายปีที่คำแนะนำด้านประสิทธิภาพเว็บฟังดูเรียบง่าย: บีบอัดทุกอย่าง minify ทุกอย่าง และทำให้ asset ทุกชิ้นเล็กลง

คำแนะนำนั้นยังคงถูกต้องในภาพรวม สคริปต์ 40 KB มักดีกว่าสคริปต์ 400 KB รูปภาพที่ปรับแต่งแล้วดีกว่าไฟล์ export ดิบ Brotli, AVIF, การ minify CSS, tree shaking และการทำ font subsetting ล้วนสำคัญ

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

หน้าเว็บหนึ่งอาจดูมีวินัยในเรื่องขนาดไฟล์ แต่ยังช้าได้ เพราะส่งคำขอ 120 รายการ: ชิ้นส่วน CSS, JavaScript chunks, แท็ก third-party, ไฟล์ฟอนต์, tracking pixels, icon sprites, JSON endpoints, preloads, analytics beacons และการตรวจสอบ cache ซ้ำ แต่ละรายการอาจ “เล็ก” แต่เมื่อรวมกันแล้ว สิ่งเหล่านี้สร้าง waterfall ที่ยาวและเปราะบาง

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

คำขอไม่ใช่แค่จำนวนไบต์

คำขอบนเครือข่ายไม่ใช่แค่การถ่ายโอนข้อมูล แต่เป็นลำดับของงานหลายขั้นตอน

เบราว์เซอร์ต้องค้นพบ resource, ตัดสินใจว่าจะ fetch เมื่อใด, จัดคิวเทียบกับ resource อื่น, ส่ง headers, รอเซิร์ฟเวอร์, รับ headers, parse response, มักต้อง decompress และจากนั้นจึงนำไปทำสิ่งที่มีประโยชน์

“สิ่งที่มีประโยชน์” นั้นอาจมีต้นทุนสูง ไฟล์ JavaScript ต้องถูก parse, compile และ execute ไฟล์ CSS อาจ block การ render ไฟล์ฟอนต์อาจทำให้ข้อความอ่านได้ช้าลงหรือทำให้ layout shifts รูปภาพอาจมีผลต่อองค์ประกอบ Largest Contentful Paint สคริปต์ third-party อาจพ่วง dependency chain ของตัวเองมาด้วย

นี่คือเหตุผลที่จำนวนคำขอยังสำคัญ แม้ไฟล์จะเล็ก สคริปต์ 3 KB อาจแย่กว่ารูปภาพ 30 KB หากมัน block การ render, มาถึงช้า และ execute บน main thread ในจังหวะที่ไม่เหมาะสม

หากคุณกำลังอ่านรายงาน Lighthouse แล้วรู้สึกเหมือนถูกลงโทษด้วยคำเตือนแยกย่อยจำนวนมาก ให้เริ่มจากการดู request waterfall แทนคะแนนแต่ละตัว เรามีคำแนะนำเชิงปฏิบัติในบทความว่าด้วยการอ่านรายงาน Lighthouse โดยไม่ตื่นตระหนก แต่ฉบับสั้นคือ: หาสิ่งที่ block first render และสิ่งที่ทำให้ main content ล่าช้า

“แต่ HTTP/2 แก้เรื่องนี้แล้ว” ส่วนใหญ่ยังไม่ใช่

HTTP/2 และ HTTP/3 เปลี่ยนเศรษฐศาสตร์ของคำขอ พวกมันนำ multiplexing, header compression และพฤติกรรมการเชื่อมต่อที่ดีขึ้นเข้ามา พูดง่าย ๆ คือ เบราว์เซอร์เก่งขึ้นมากในการส่งหลายคำขอผ่านการเชื่อมต่อที่น้อยลง

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

แต่ HTTP/2 ไม่ได้ทำให้คำขอฟรี

Multiplexing ช่วยเมื่อ resource จำนวนมากใช้การเชื่อมต่อร่วมกัน แต่เบราว์เซอร์ยังต้องจัดลำดับความสำคัญของมัน เซิร์ฟเวอร์ยังต้องตอบกลับ client ยังต้องประมวลผล response แต่ละรายการ congestion, packet loss, TLS negotiation, DNS lookup, cache misses และแรงกดดันบน main thread ก็ยังมีอยู่

HTTP/3 ปรับปรุงพฤติกรรมของ transport บางส่วน โดยเฉพาะเรื่อง connection migration และ head-of-line blocking ที่ชั้น transport แต่มันไม่ได้ลบต้นทุนของการค้นพบ การจัดคิว การดาวน์โหลด การ parse และการ execute resource

ดังนั้นเป้าหมายสมัยใหม่จึงไม่ใช่ “รวมทุกอย่างเป็นไฟล์มหึมาไฟล์เดียว” แต่คือ “ส่ง critical requests ให้น้อยลง และทำให้คำขอที่เหลือมีเจตนาชัดเจน”

Waterfall คือที่ที่ความจริงอยู่

ปัญหาด้านประสิทธิภาพแทบไม่เคยประกาศตัวเองใน metric เดียว มันปรากฏออกมาเป็นรูปทรง

เปิด browser network panel แล้วดูช่วงสองสามวินาทีแรก ถามว่า:

  • มีคำขอกี่รายการเริ่มก่อนที่ main content จะปรากฏ?
  • คำขอใด block การ render?
  • resource สำคัญถูกค้นพบช้าหรือไม่?
  • สคริปต์ third-party กำลังแย่งทรัพยากรกับ CSS, ฟอนต์ หรือรูปภาพ first-party หรือไม่?
  • มีไฟล์จำนวนมากตอบกลับเป็น 304 แทนที่จะถูกเสิร์ฟจาก cache โดยตรงหรือไม่?
  • icons, fonts หรือ UI fragments ถูกแยกเป็นไฟล์มากเกินกว่าที่หน้านั้นต้องการหรือไม่?

หน้าเว็บที่เร็วโดยทั่วไปมี early waterfall ที่น่าเบื่อ resource สำคัญจำนวนเล็กน้อยมาถึงเร็ว resource ที่ไม่สำคัญรอไปก่อน สคริปต์ third-party ถูกหน่วง จำกัด หรือลบออก เบราว์เซอร์ไม่ถูกบังคับให้ต้องจัดการความสำคัญยี่สิบรายการก่อนที่จะ paint หน้าได้

หน้าเว็บที่ช้ามักมี waterfall ที่กระวนกระวาย: ไฟล์เล็กจำนวนมาก origins จำนวนมาก และการค้นพบที่มาช้าอีกมาก

ไฟล์ที่เล็กลงยังสำคัญ — แค่ไม่สำคัญเท่ากันทั้งหมด

นี่ไม่ใช่ข้อโต้แย้งต่อการบีบอัดหรือการปรับแต่ง แต่เป็นข้อโต้แย้งต่อการปรับแต่งจำนวนไบต์โดยไม่สนใจการประสานงาน

ไฟล์ที่เล็กลงสำคัญที่สุดเมื่อ resource นั้นมีขนาดใหญ่, block การ render หรือเป็นส่วนหนึ่งของเส้นทาง main content ตัวอย่างเช่น:

  • Hero image ควรถูกปรับขนาดและ encode อย่างเหมาะสม
  • CSS ที่ block การ render ควรกะทัดรัด
  • JavaScript ที่จำเป็นต่อ first interaction ควรน้อยที่สุด
  • ฟอนต์ควรถูก subset, บีบอัด และจำกัดเฉพาะ weights ที่ใช้จริง

ฟอนต์เป็นตัวอย่างที่พบได้บ่อย ทีมมักหมกมุ่นว่าไฟล์ฟอนต์มีขนาด 24 KB หรือ 31 KB ขณะที่ส่งหก weights, สอง styles และหลาย families วิธีแก้ที่ดีกว่าไม่ใช่การไล่ลด 7 KB จากไฟล์เดียว แต่คือการส่งไฟล์ฟอนต์ให้น้อยลง หาก typography เป็นส่วนหนึ่งของงานด้านประสิทธิภาพของคุณ web fonts ยังคงเป็นหนึ่งในชัยชนะที่ง่ายที่สุดบนเว็บไซต์ส่วนใหญ่

รูปภาพก็เป็นรูปแบบเดียวกัน AVIF หรือ WebP อาจช่วยประหยัดไบต์ได้อย่างมีนัยสำคัญ แต่การส่งรูปตกแต่งสิบภาพ above the fold ก็ยังเป็นแผนที่ไม่ดี เลือก format ที่ดีกว่าได้ ใช่ แต่ควรถามด้วยว่ารูปแต่ละภาพจำเป็นต้องถูก request เลยหรือไม่ สำหรับการตัดสินใจเรื่อง format คู่มือของเราเรื่อง เมื่อใดที่ AVIF เหนือกว่า WebP และเมื่อใดที่ไม่ใช่ เป็นคู่ประกอบที่มีประโยชน์กับงานลดจำนวนคำขอนี้

ต้นทุนที่ซ่อนอยู่ของไฟล์เล็กจำนวนมาก

คำขอเล็ก ๆ จำนวนมากมักสร้างปัญหาที่ไม่ปรากฏหากคุณดูเฉพาะจำนวนไบต์ที่ถ่ายโอนทั้งหมด

1. การค้นพบที่ล่าช้า

เบราว์เซอร์ไม่สามารถ request สิ่งที่ยังไม่ค้นพบ ไฟล์ CSS อาจอ้างอิงฟอนต์ สคริปต์อาจ import สคริปต์อีกตัว component อาจ request JSON หลัง hydration dependency แต่ละรายการสร้างอีกขั้นหนึ่งใน chain

ยิ่ง chain ลึก งานสำคัญก็ยิ่งเริ่มช้า

2. ค่าใช้จ่ายของ headers

ทุก request และ response มี headers การบีบอัด header ช่วยได้ โดยเฉพาะบน HTTP/2 และ HTTP/3 แต่ไม่ได้กำจัดค่าใช้จ่ายนี้ Cookies อาจทำให้เรื่องนี้แย่ลงมาก หากเว็บไซต์ของคุณส่ง cookies ขนาดใหญ่ไปกับทุก request ในทางปฏิบัติ asset ขนาดจิ๋วจะไม่จิ๋วเท่าเดิม

นี่เป็นเหตุผลหนึ่งที่ static assets มักควรอยู่บน paths หรือ domains ที่ไม่มี cookie และเป็นเหตุผลว่าทำไม cache headers จึงควรได้รับความใส่ใจ หาก headers ทำตัวแปลก ๆ ใน production การ debug redirects และ HTTP headers มักเร็วกว่าการเดา

3. การขัดจังหวะ main thread

JavaScript chunks จำนวนมากอาจสร้างงาน parse และ execution ซ้ำ ๆ แม้แต่ละ chunk จะเล็ก เบราว์เซอร์อาจต้องหยุดเป็นระยะเพื่อ evaluate code สิ่งนี้อาจกระทบ Interaction to Next Paint และทำให้หน้าเว็บรู้สึกกระตุก

ผู้ใช้ไม่ได้สนใจว่าแต่ละไฟล์เล็กแค่ไหน พวกเขาสนใจว่าการแตะเมนูใช้เวลา 600 milliseconds

4. ความซับซ้อนของ cache

การแยก asset สามารถปรับปรุง caching ได้ หากทำอย่างรอบคอบ vendor bundle ที่เสถียรและ app bundle ที่เปลี่ยนแปลงได้อาจเป็นการแบ่งที่ดี

แต่การทำ chunking มากเกินไปอาจย้อนกลับมาทำร้ายได้ ไฟล์ที่มากขึ้นหมายถึง cache lookups ที่มากขึ้น โอกาส revalidation ที่มากขึ้น การประสาน version ที่มากขึ้น และช่องทางมากขึ้นในการเผลอ invalidate resource ที่ไม่จำเป็นต้องเปลี่ยน

Bundling กลับมาแล้ว แต่ต้องใช้วิจารณญาณ

ยุคแรกของ web performance ชอบ bundling เพราะเบราว์เซอร์มีขีดจำกัดการเชื่อมต่อที่เข้มงวด จากนั้น HTTP/2 มาถึง และหลายทีมก็เหวี่ยงไปทาง aggressive code splitting อย่างแรง บางส่วนมีประโยชน์ บางส่วนกลายเป็นความเชื่อที่ทำตามกันมา

ทางสายกลางที่สมเหตุสมผลคือ route-aware bundling

สำหรับเว็บไซต์ marketing หรือ content site ทั่วไป:

  • Inline หรือ load เฉพาะ CSS ที่จำเป็นต่อ initial rendering
  • รักษา global JavaScript ให้เล็ก
  • หลีกเลี่ยงการแยก modules ขนาดจิ๋วเป็น network requests แยกกัน
  • หน่วง interactive features ที่ยังไม่จำเป็นทันที
  • ลบสคริปต์ third-party ที่ไม่คุ้มกับต้นทุนของมัน

สำหรับ application:

  • แยกตาม route หรือ feature หลัก ไม่ใช่ตามทุก component
  • รักษา shared dependencies ให้เสถียรและ cache ได้
  • Preload เฉพาะ resource ที่จำเป็นแน่นอนในเร็ว ๆ นี้
  • หลีกเลี่ยงการโหลด code ของ admin, dashboard, editor หรือ experiment บน public pages
  • วัดต้นทุนด้าน interaction ไม่ใช่แค่ขนาด bundle

Bundling ไม่ได้ดีโดยอัตโนมัติ Code splitting ก็ไม่ได้ดีโดยอัตโนมัติ คำถามที่มีประโยชน์คือ: การแบ่งแบบนี้ช่วยให้เบราว์เซอร์ส่งมอบประสบการณ์ผู้ใช้ที่มีความหมายถัดไปได้เร็วขึ้นหรือไม่?

คำขอจาก third-party ควรถูกสงสัยเป็นพิเศษ

อย่างน้อยคำขอ first-party ก็อยู่ภายใต้การควบคุมของคุณ คำขอ third-party มักช้ากว่า คาดเดาได้น้อยกว่า และแพงกว่าที่เห็น

tag manager เพียงตัวเดียวอาจกระตุ้น analytics, ads, heatmaps, chat widgets, A/B testing, consent tools และ personalization scripts vendor แต่ละรายอาจพ่วงคำขอเพิ่ม บางตัวจะทำงานตั้งแต่ต้น บางตัวจะ block main thread บางตัวจะเปลี่ยนโดยไม่ผ่าน release process ของคุณ

การปรับแต่ง third-party ที่ดีที่สุดคือการลบ สิ่งที่ดีที่สุดรองลงมาคือการหน่วง

ก่อนเพิ่มสคริปต์ third-party ให้ถามว่า:

  • สิ่งนี้จำเป็นต้อง load ก่อนที่ผู้ใช้จะเห็นหน้าหรือไม่?
  • จำเป็นต้อง load ในทุกหน้าหรือไม่?
  • สามารถ load หลัง consent, interaction หรือ idle time ได้หรือไม่?
  • ใครเป็นเจ้าของภายในองค์กร?
  • metric ใดพิสูจน์ได้ว่ามันคุ้มกับต้นทุนด้านประสิทธิภาพ?

นี่คือจุดที่ performance กลายเป็น governance ต้องมีใครสักคนที่ได้รับอนุญาตให้พูดว่าไม่

Checklist เชิงปฏิบัติสำหรับการลดคำขอ

เริ่มจากหน้าที่สำคัญที่สุด: homepage, pricing page, product page, checkout, signup หรือ landing pages อันดับต้น ๆ จากนั้นไล่ตรวจ waterfall

ลบ

  • ลบ JavaScript และ CSS ที่ไม่ได้ใช้
  • ลบ experiments เก่า, pixels ที่ถูกทิ้งไว้ และ analytics ที่ซ้ำซ้อน
  • ตัด font weights และ icon libraries ที่ไม่ได้ใช้
  • แทนที่รูปภาพตกแต่งด้วย CSS เมื่อเหมาะสม

รวมอย่างรอบคอบ

  • Bundle JavaScript modules ขนาดจิ๋วที่มัก load พร้อมกันเสมอ
  • รวมไฟล์ CSS เล็ก ๆ ที่ block render path เดียวกัน
  • ใช้ SVG sprites หรือ inline SVG สำหรับ icons ที่ใช้ซ้ำ เมื่อช่วยลดคำขอโดยไม่กระทบ maintainability

หน่วง

  • Lazy-load รูปภาพ below-the-fold
  • หน่วงสคริปต์ที่ไม่สำคัญจนกว่าจะหลัง first paint หรือ user interaction
  • Load comments, embeds, maps, chat และ video players เฉพาะเมื่อจำเป็น

Cache อย่างเหมาะสม

  • ใช้ caching อายุยาวสำหรับ versioned static assets
  • หลีกเลี่ยง revalidation ที่ไม่จำเป็นสำหรับไฟล์ที่แทบไม่เปลี่ยน
  • รักษา HTML ให้สดใหม่ แต่ปล่อยให้ hashed assets อยู่ใน cache ต่อไป

วัดใหม่

หลังการเปลี่ยนแปลงแต่ละครั้ง ให้ตรวจ waterfall อีกครั้ง เป้าหมายไม่ใช่คะแนนที่สมบูรณ์แบบ เป้าหมายคือ critical requests ที่น้อยลง useful rendering ที่เร็วขึ้น และการรบกวน main thread ที่ลดลง

หน้าตาที่ดีเป็นอย่างไร

หน้าเว็บที่แข็งแรงไม่จำเป็นต้องมีคำขอน้อยที่สุดเท่าที่เป็นไปได้ แต่มี critical path ที่เล็กและตั้งใจออกแบบ

เบราว์เซอร์ได้รับ HTML, CSS ที่จำเป็น, รูปภาพ main content หากมี, อาจมีสคริปต์เล็ก ๆ ที่จำเป็นต่อ navigation หรือ interaction above-the-fold และชุดฟอนต์ขั้นต่ำที่ทำให้ข้อความอ่านได้ สิ่งอื่นทั้งหมดรอคิวของมัน

นั่นคือความแตกต่างระหว่างหน้าที่เพียงแค่ถูกปรับแต่ง กับหน้าที่รู้สึกว่าเร็ว

การลดขนาดไฟล์ยังคุ้มค่าที่จะทำ แต่หากเว็บไซต์ถูกบีบอัดอย่างเหมาะสมอยู่แล้ว ชัยชนะด้านประสิทธิภาพถัดไปมักไม่ใช่การประหยัดอีก 2 KB จาก bundle แต่คือคำขอที่ block น้อยลงหนึ่งรายการ ไฟล์ฟอนต์น้อยลงหนึ่งไฟล์ สคริปต์ third-party น้อยลงหนึ่งตัว dependency chain น้อยลงหนึ่งสาย

คำขอที่น้อยลงทำให้งานของเบราว์เซอร์เรียบง่ายขึ้น และความเรียบง่ายมักเร็วกว่า มากกว่าที่เราชอบยอมรับ

คำถามที่พบบ่อย

Bundle ขนาดใหญ่ไฟล์เดียวดีกว่าไฟล์เล็กหลายไฟล์หรือไม่?
ไม่ใช่โดยอัตโนมัติ Bundle ขนาดมหึมาไฟล์เดียวอาจทำให้ทุกอย่างล่าช้า โดยเฉพาะในการโหลดครั้งแรก ไฟล์จิ๋วจำนวนมากอาจสร้างค่าใช้จ่ายด้านการจัดคิวและ execution รูปแบบที่ดีกว่าคือ bundle resource ที่ต้องใช้ร่วมกันเสมอ และแยกตาม route หรือ feature หลัก
HTTP/2 หมายความว่าจำนวนคำขอไม่สำคัญอีกต่อไปหรือไม่?
ไม่ใช่ HTTP/2 ลดค่าใช้จ่ายด้านการเชื่อมต่อบางส่วนผ่าน multiplexing และ header compression แต่แต่ละคำขอยังมีต้นทุนด้านการค้นพบ การจัดลำดับความสำคัญ เซิร์ฟเวอร์ cache การ parse และ execution
ฉันควร inline critical CSS ทั้งหมดหรือไม่?
การ inline CSS ที่ critical จริง ๆ ในปริมาณเล็กน้อยอาจช่วย first render ได้ แต่การ inline มากเกินไปทำให้ HTML หนักขึ้นและ cache ได้ยากขึ้น ควรรักษาให้ minimal และวัดผลกระทบ
จุดที่ง่ายที่สุดในการลดคำขอคืออะไร?
ฟอนต์และสคริปต์ third-party มักเป็นชัยชนะที่เร็วที่สุด เว็บไซต์จำนวนมากส่ง font weights ที่ไม่ได้ใช้, analytics ซ้ำซ้อน, pixels เก่า, chat widgets หรือ embeds ที่ไม่จำเป็นต้อง load ทันที
หน้าเว็บควรมีคำขอกี่รายการ?
ไม่มีเป้าหมายสากล หน้า content ขนาดเล็กควรมี critical requests น้อยมาก application ที่ซับซ้อนอาจต้องมีมากกว่า ให้เน้นลดคำขอก่อน first render และก่อนเส้นทาง main interaction

แหล่งข้อมูล & การอ่านเพิ่มเติม

  1. MDN Web Docs: HTTP caching
  2. web.dev: Optimize Largest Contentful Paint
  3. RFC 9113: HTTP/2
  4. HTTP Archive Web Almanac: Page Weight
เกี่ยวกับผู้เขียน
The Wux Webtools Team

อัปเดตล่าสุด:

อ่านต่อ

Web Performance

ทำไม Time to First Byte ของคุณจึงช้า และควรทำอย่างไร

TTFB ที่ช้ามักหมายถึงการกำหนดเส้นทางที่ช้า, แคชที่หายไป, เซิร์ฟเวอร์รับภาระเกิน หรือการทำงานฝั่ง backend ที่มีต้นทุนสูง ต่อไปนี้คือวิธีวินิจฉัยและแก้ไข

23 อ่านขั้นต่ำ