การขัดขวาง 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() อาจทำให้การแสดงเนื้อหาหลักของหน้าช้าลงหลาย 10 วินาที หรือทำให้หน้าเว็บโหลดไม่สำเร็จหรือใช้เวลานานมากจนผู้ใช้เลิกอ่าน จากการใช้เครื่องมือใน 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 แล้วแจ้งระบบการวิเคราะห์หรือเมตริกผู้ใช้จริง (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 นี้

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

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