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

เมื่อเร็วๆ นี้คุณเห็นคำเตือนต่อไปนี้ในคอนโซลนักพัฒนาซอฟต์แวร์ใน 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() มักจะโหลดช้ากว่าหน้าอื่นๆ 2 เท่าในเครือข่าย 2G

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

  • การโหลดหน้าเว็บที่ไปถึงFirst Contentful Paint (การยืนยันด้วยภาพว่าหน้าเว็บโหลดได้อย่างมีประสิทธิภาพ) เพิ่มขึ้น10% การโหลดหน้าเว็บที่ไปถึงสถานะแยกวิเคราะห์อย่างสมบูรณ์เพิ่มขึ้น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.written ภายใน 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 สําหรับสคริปต์ (แบบไม่สอดคล้องกันในกรณีที่มีการแทรกแซงจริง)

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

แผนเริ่มต้นคือการดําเนินการแทรกแซงนี้เมื่อเราตรวจพบว่ามีคุณสมบัติตรงตามเกณฑ์ เราเริ่มด้วยการแสดงคำเตือนในคอนโซลของนักพัฒนาซอฟต์แวร์ใน Chrome 53 (เวอร์ชันเบต้าเปิดตัวเมื่อเดือนกรกฎาคม 2016 เราคาดว่าเวอร์ชันเสถียรจะพร้อมให้บริการแก่ผู้ใช้ทุกคนในเดือนกันยายน 2016)

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

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

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

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