การขัดขวาง 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.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

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

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