หน้าแรกของเว็บนี้มีฉาก 3D ที่เขียนด้วย Three.js บนเครื่องของเราซึ่งมี GPU มันลื่นปกติ แต่เมื่อเอาไปวัดใน PageSpeed คะแนนเดสก์ท็อปอยู่ที่ 45 ถึง 63 และ Total Blocking Time อยู่ที่ 0.9 ถึง 3.9 วินาที
ช่องว่างระหว่างสองอย่างนี้คือเรื่องของบทความนี้ เครื่องวัดไม่ได้ผิด มันเป็นเครื่องคนละแบบ และการเข้าใจว่าต่างกันตรงไหนคือทั้งหมดของการแก้
เครื่องวัดไม่ใช่คอมพิวเตอร์ของลูกค้า
ห้องแล็บของ PageSpeed รัน Chrome บนเซิร์ฟเวอร์ที่ไม่มี GPU เมื่อหน้าเว็บขอ WebGL เบราว์เซอร์จึงใช้ตัวเรนเดอร์แบบซอฟต์แวร์ที่ชื่อ SwiftShader แทน มันทำงานได้ แต่ใช้ CPU ล้วน และแค่การสร้าง WebGL2 context ขึ้นมาก็กินเวลาราวหนึ่งวินาทีบน main thread ช่วงนั้นหน้าเว็บกดอะไรไม่ได้ ซึ่งคือสิ่งที่ Total Blocking Time วัดอยู่พอดี

ทางที่ไม่พอ: ถามเบราว์เซอร์ตรง ๆ
ตัวเลือก failIfMajorPerformanceCaveat ของ WebGL ออกแบบมาให้การสร้าง context ล้มเหลวเมื่อเบราว์เซอร์จะต้องใช้ตัวเรนเดอร์ที่ช้า เราลองแล้ว แต่มันจับ SwiftShader ไม่ได้ จึงไม่ช่วยอะไร
ครั้งแรกเราจึงดักตอนสร้าง context แล้วอ่านชื่อตัวเรนเดอร์ ถ้าชื่อบอกว่าเป็นซอฟต์แวร์ก็ส่งค่าว่างกลับไป ให้ฉาก 3D ถอยไปใช้ภาพโปสเตอร์แทน วิธีนี้ติดอยู่ข้อเดียว การจะอ่านชื่อตัวเรนเดอร์ได้ต้องสร้าง context ก่อน และการสร้างนั้นแหละคือหนึ่งวินาทีที่เราอยากเลี่ยง
วิธีที่ได้ผล: ให้คนอื่นไปลองแทน
Web Worker ทำงานนอก main thread และสร้าง OffscreenCanvas ได้ เราจึงให้ Worker เล็ก ๆ ตัวหนึ่งไปสร้าง WebGL2 context บนแคนวาส 1×1 พิกเซล อ่านชื่อตัวเรนเดอร์ แล้วส่งคำตอบกลับมา จริงถ้าเป็นการ์ดจอจริง เท็จถ้าชื่อมี swiftshader, llvmpipe, softpipe หรือ software และว่างเปล่าถ้าบอกไม่ได้ หน้าเว็บไม่ต้องรอหรือจ่ายหนึ่งวินาทีนั้นเลย
สคริปต์ในหัวของหน้าแรกเริ่ม Worker ตั้งแต่ก่อนโหลดโค้ดอื่น และเก็บคำตอบไว้ให้ฉาก 3D มาอ่าน มีสามรายละเอียดที่ทำให้มันใช้ได้จริง
ไม่มีคำตอบภายใน 5 วินาทีถือว่าไม่มี GPU เพราะเครื่องที่ไม่มี GPU และกำลังถูกบีบมักตอบช้า การถอยไปใช้ภาพโปสเตอร์ปลอดภัยกว่าการรอ
จอที่กว้างไม่ถึง 700 พิกเซลข้ามการตรวจ เพราะมือถือไม่สร้างฉาก 3D อยู่แล้ว
Worker ต้องเป็นไฟล์จริง ไม่ใช่ Blob เพราะนโยบาย CSP ของเว็บไม่อนุญาต blob: ใน script-src และเราไม่ขยาย CSP เพื่อความสะดวก ไฟล์นั้นคือ /static/gl-probe.js

ผลที่ได้
ก่อนแก้ การวัดบนเดสก์ท็อปได้ 45 ถึง 63 คะแนน และ Total Blocking Time 0.9 ถึง 3.9 วินาที หลังแก้ เมื่อวันที่ 15 ตุลาคม 2569 เรารัน Lighthouse 13.5 สามรอบบนเดสก์ท็อป ได้ 74, 79 และ 83 คะแนน และ Total Blocking Time เป็น 0 มิลลิวินาทีทั้งสามรอบ

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


