การขัดขวาง document.write()

เมื่อเร็วๆ นี้คุณเห็นคำเตือนที่มีลักษณะดังต่อไปนี้ใน Developer Console ใน Chrome หรือไม่ และสงสัยว่าข้อความนี้คืออะไร

(index):34 A Parser-blocking, cross-origin script,
https://paul.kinlan.me/ad-inject.js, is invoked via document.write().
This may be blocked by the browser if the device has poor network connectivity.

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

หนึ่งในสาเหตุที่ทราบว่าให้ประสิทธิภาพไม่ดีคือการใช้ document.write() ภายในหน้าเว็บ โดยเฉพาะที่ใช้การแทรกสคริปต์ ดังที่เห็นแล้วไม่น่าเป็นห่วง อาจสร้างปัญหาที่แท้จริงให้กับผู้ใช้ได้

document.write('<script src="https://example.com/ad-inject.js"></script>');

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

สำหรับผู้ใช้ที่มีการเชื่อมต่อที่ช้า เช่น 2G สคริปต์ภายนอกที่แทรกเข้ามาแบบไดนามิกผ่าน document.write() อาจหน่วงเวลาการแสดงเนื้อหาหลักของหน้าไปหลายสิบวินาที หรือทำให้หน้าเว็บโหลดไม่สำเร็จหรือใช้เวลานานเกินไปจนผู้ใช้ปิดไป จากการใช้เครื่องมือใน Chrome เราได้เรียนรู้ว่าหน้าเว็บที่มีสคริปต์ของบุคคลที่สามที่แทรกผ่าน document.write() มักจะโหลดได้ช้ากว่าหน้าอื่นๆ ในเครือข่าย 2G ถึง 2 เท่า

เราเก็บรวบรวมข้อมูลจากช่วงทดลองใช้งานภาคสนาม 28 วันกับผู้ใช้ Chrome เวอร์ชันเสถียร 1% โดยจำกัดไว้เฉพาะผู้ใช้ที่ใช้การเชื่อมต่อ 2G เราพบว่า 7.6% ของการโหลดหน้าเว็บทั้งหมดบน 2G มีสคริปต์บล็อกโปรแกรมแยกวิเคราะห์แบบข้ามเว็บไซต์อย่างน้อย 1 รายการที่แทรกผ่าน document.write() ในเอกสารระดับบนสุด การบล็อกการโหลดสคริปต์เหล่านี้ทำให้เราเห็นการปรับปรุงดังต่อไปนี้ในการโหลดสคริปต์ดังกล่าว

  • การโหลดหน้าเว็บเพิ่มขึ้น 10% ที่ถึง First Contentful Paint (ภาพยืนยันสำหรับผู้ใช้ว่าหน้าเว็บกำลังโหลดอย่างมีประสิทธิภาพ) มีการโหลดหน้าเว็บมากขึ้น 25% ที่ถึงสถานะการแยกวิเคราะห์อย่างสมบูรณ์ และการโหลดซ้ำน้อยลง 10% ทำให้ผู้ใช้รู้สึกหงุดหงิดน้อยลง
  • เวลาเฉลี่ยลดลง 21% (เร็วกว่า 1 วินาที) จนถึง First Contentful Paint
  • ลดเวลาเฉลี่ยในการแยกวิเคราะห์หน้าเว็บลง 38% ซึ่งเพิ่มขึ้นเกือบ 6 วินาที ซึ่งช่วยประหยัดเวลาในการแสดงสิ่งที่สำคัญต่อผู้ใช้ได้อย่างมาก

เมื่อคำนึงถึงข้อมูลนี้ Chrome ซึ่งเริ่มตั้งแต่เวอร์ชัน 55 จะแทรกแซงในนามของผู้ใช้ทั้งหมดเมื่อเราตรวจพบรูปแบบที่ไม่ดีซึ่งเป็นที่รู้จักนี้โดยเปลี่ยนวิธีจัดการ document.write() ใน Chrome (ดูสถานะของ Chrome) กล่าวโดยละเอียดคือ Chrome จะไม่เรียกใช้เอลิเมนต์ <script> ที่แทรกผ่าน document.write() เมื่อเป็นไปตามเงื่อนไขทั้งหมดต่อไปนี้

  1. ผู้ใช้อยู่ในการเชื่อมต่อที่ช้า โดยเฉพาะเมื่อผู้ใช้ใช้ 2G (ในอนาคต การเปลี่ยนแปลงอาจมีผลกับผู้ใช้คนอื่นๆ ที่การเชื่อมต่อช้า เช่น 3G หรือ Wi-Fi ช้า)
  2. document.write() อยู่ในเอกสารระดับบนสุด การฝึกฝนนี้ไม่ใช้กับสคริปต์ document.write ภายใน iframe เนื่องจากไม่ได้บล็อกการแสดงหน้าหลัก
  3. สคริปต์ใน document.write() กำลังบล็อกโปรแกรมแยกวิเคราะห์ สคริปต์ที่มีแอตทริบิวต์ "async" หรือ "defer" จะยังคงดำเนินการอยู่
  4. สคริปต์ไม่ได้โฮสต์อยู่ในเว็บไซต์เดียวกัน กล่าวคือ Chrome จะไม่แทรกแซงสคริปต์ที่มี eTLD+1 ที่ตรงกัน (เช่น สคริปต์ที่โฮสต์ใน js.example.org ซึ่งแทรกไว้ใน www.example.org)
  5. สคริปต์ไม่ได้อยู่ในแคช HTTP ของเบราว์เซอร์แล้ว สคริปต์ในแคชจะไม่ก่อให้เกิดความล่าช้าของเครือข่ายและจะยังคงดำเนินการอยู่
  6. คำขอสำหรับหน้านี้ไม่ใช่การโหลดซ้ำ Chrome จะไม่เข้าไปแทรกแซงถ้าผู้ใช้ทริกเกอร์การโหลดซ้ำและจะทำงานตามปกติ

บางครั้งข้อมูลโค้ดของบุคคลที่สามจะใช้ document.write() เพื่อโหลดสคริปต์ โชคดีที่บุคคลที่สามส่วนใหญ่มีทางเลือกในการโหลดแบบอะซิงโครนัส ซึ่งช่วยให้สคริปต์ของบุคคลที่สามโหลดได้โดยไม่บล็อกการแสดงเนื้อหาที่เหลือในหน้า

ฉันจะแก้ไขปัญหานี้ได้อย่างไร

คำตอบง่ายๆ นี้คือไม่แทรกสคริปต์โดยใช้ document.write() เราดูแลรักษาชุดบริการที่รู้จักสำหรับการรองรับตัวโหลดแบบไม่พร้อมกันที่เราขอแนะนำให้คุณตรวจสอบต่อไป

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

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

หากผู้ให้บริการให้ข้อมูลโค้ดที่มี document.write() แก่คุณ คุณก็อาจเพิ่มแอตทริบิวต์ async ลงในองค์ประกอบสคริปต์ หรือเพิ่มองค์ประกอบสคริปต์ที่มี DOM API เช่น document.appendChild() หรือ parentNode.insertBefore() ได้

วิธีตรวจหาเมื่อเว็บไซต์ของคุณได้รับผลกระทบ

มีเกณฑ์จำนวนมากที่ใช้พิจารณาว่ามีข้อจำกัดหรือไม่ แล้วคุณจะรู้ได้อย่างไรว่าได้รับผลกระทบหรือไม่

ตรวจจับเมื่อผู้ใช้ใช้งาน 2G

เพื่อทำความเข้าใจผลกระทบที่อาจเกิดขึ้นของการเปลี่ยนแปลงนี้ ก่อนอื่นคุณต้องเข้าใจจำนวนผู้ใช้ที่จะใช้ 2G คุณตรวจหาประเภทและความเร็วเครือข่ายปัจจุบันของผู้ใช้ได้โดยใช้ Network Information API ที่มีให้ใช้งานใน Chrome จากนั้นส่งคำเตือนไปยังระบบ Analytic หรือระบบเมตริกผู้ใช้จริง (RUM)

if(navigator.connection &&
    navigator.connection.type === 'cellular' &&
    navigator.connection.downlinkMax <= 0.115) {
    // Notify your service to indicate that you might be affected by this restriction.
}

ตรวจจับคำเตือนในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome

ตั้งแต่ Chrome 53 เครื่องมือสำหรับนักพัฒนาเว็บจะออกคำเตือนสำหรับคำสั่ง document.write() ที่เป็นปัญหา โดยเฉพาะอย่างยิ่ง หากคำขอ document.write() ตรงตามเกณฑ์ 2 ถึง 5 (Chrome จะไม่สนใจเกณฑ์การเชื่อมต่อเมื่อส่งคำเตือนนี้) คำเตือนจะมีลักษณะดังนี้

คำเตือนในการเขียนเอกสาร

การเห็นคำเตือนในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome เป็นเรื่องดี แต่คุณจะตรวจพบคำเตือนในวงกว้างได้อย่างไร คุณสามารถตรวจสอบส่วนหัว HTTP ที่ส่งไปยังเซิร์ฟเวอร์ของคุณเมื่อมีการแทรกแซงเกิดขึ้นได้

ตรวจสอบส่วนหัว HTTP ในทรัพยากรของสคริปต์

เมื่อสคริปต์ที่แทรกผ่าน document.write ถูกบล็อก Chrome จะส่งส่วนหัวต่อไปนี้ไปยังทรัพยากรที่ขอ

Intervention: <https://shorturl/relevant/spec>;

เมื่อพบสคริปต์ที่แทรกผ่าน document.write และอาจถูกบล็อกในสถานการณ์ที่ต่างกัน Chrome อาจส่งรายการต่อไปนี้

Intervention: <https://shorturl/relevant/spec>; level="warning"

ระบบจะส่งส่วนหัวการฝึกฝนเป็นส่วนหนึ่งของคำขอ GET สำหรับสคริปต์ (ไม่พร้อมกันในกรณีที่มีการดำเนินการจริง)

มีอะไรรอเราอยู่บ้างในอนาคต

แผนเริ่มต้นคือการฝึกฝนนี้เมื่อตรวจพบว่ามีคุณสมบัติตรงตามเกณฑ์ เราเริ่มจากการแสดงเพียงคำเตือนใน Developer Console ใน Chrome 53 (รุ่นเบต้าอยู่ในเดือนกรกฎาคม 2016 เราคาดว่าเวอร์ชันเสถียรจะพร้อมใช้งานสำหรับผู้ใช้ทุกคนในเดือนกันยายน 2016)

เราจะเข้าไปบล็อกสคริปต์ที่แทรกไว้สำหรับผู้ใช้ 2G ในเบื้องต้นใน Chrome 54 ซึ่งคาดว่าจะเป็นเวอร์ชันเสถียรสำหรับผู้ใช้ทุกคนในช่วงกลางเดือนตุลาคม 2016 ดูรายการสถานะ Chrome สำหรับการอัปเดตเพิ่มเติม

เมื่อเวลาผ่านไป เราต้องการที่จะเข้ามาแทรกแซงในกรณีที่การเชื่อมต่อของผู้ใช้ช้า (เช่น 3G หรือ Wi-Fi ที่ช้า) ทำตามรายการสถานะของ Chrome

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

ดูข้อมูลเพิ่มเติมได้จากแหล่งข้อมูลต่อไปนี้