ส่วนขยายของ Chrome: การขยาย API เพื่อรองรับการนำทางแบบทันที

เดฟ ตาปูสกา
Dave Tapuska

TL;DR: Extensions API ได้รับการอัปเดตเพื่อรองรับฟีเจอร์ Back-Forward Cache และการโหลดล่วงหน้า โปรดดูรายละเอียดด้านล่าง

Chrome ทุ่มเทอย่างเต็มที่เพื่อทำให้การนำทางรวดเร็ว เทคโนโลยีการนำทางทันใจอย่าง Back/Forward Cache (จัดส่งแล้วบนเดสก์ท็อปใน Chrome 96) และกฎการคาดเดา (จัดส่งแล้วใน Chrome 103) จะช่วยปรับปรุงประสบการณ์การใช้งานย้อนกลับและไปข้างหน้า ในโพสต์นี้ เราจะสำรวจอัปเดตที่เราทำกับ API ส่วนขยายเบราว์เซอร์เพื่อรองรับเวิร์กโฟลว์ใหม่เหล่านี้

การทำความเข้าใจประเภทของหน้าเว็บ

ก่อนที่จะมีการเปิดตัว Back-Forward Cache และการแสดงผลล่วงหน้า แต่ละแท็บจะมีหน้าที่ใช้งานอยู่เพียงหน้าเดียวเท่านั้น นี่คือรายการที่มองเห็นได้เสมอ หากผู้ใช้กลับไปยังหน้าก่อนหน้า หน้าที่ใช้งานอยู่จะถูกทำลาย (หน้า ข) และหน้าก่อนหน้าในประวัติการเข้าชมจะได้รับการสร้างขึ้นใหม่ทั้งหมด (หน้า ก) ส่วนขยายไม่จำเป็นต้องกังวลเกี่ยวกับส่วนใดของหน้าวงจรตลอดอายุการใช้งานเพราะมีเพียงแท็บเดียวในแท็บ นั่นก็คือสถานะ "ใช้งานอยู่/มองเห็นได้"

การนําหน้าที่ใช้งานอยู่ออก
การนําหน้าที่ใช้งานอยู่ออก

เมื่อใช้ Back-Forward Cache และการแสดงผลล่วงหน้า แท็บและหน้าต่างๆ จะไม่มีความสัมพันธ์แบบ 1 ต่อ 1 อีกต่อไป ตอนนี้ แต่ละแท็บจะจัดเก็บหน้าเว็บหลายหน้าและหน้าที่เปลี่ยนผ่านระหว่างสถานะ แทนที่จะถูกทำลายและสร้างขึ้นใหม่

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

ประเภทของหน้าเว็บ
ประเภทของหน้า

โปรดทราบว่าแท็บอาจมีชุดหน้าที่แสดงผลล่วงหน้า (ไม่ใช่เพียงหน้าเดียว) หน้าที่ใช้งานอยู่ (แสดง) หน้าเดียว และชุดหน้าที่แคชไว้ย้อนหลัง

มีอะไรเปลี่ยนแปลงบ้างสำหรับนักพัฒนาส่วนขยาย

รหัสเฟรม == 0

ใน Chromium เราจะเรียกว่าเฟรมบนสุด/เฟรมหลักเป็นเฟรมด้านนอกสุด

ผู้เขียนส่วนขยายที่ถือว่า frameId ของเฟรมด้านนอกสุดเป็น 0 (แนวทางปฏิบัติแนะนำก่อนหน้านี้) อาจมีปัญหา เนื่องจากตอนนี้แท็บสามารถมีเฟรมด้านนอกสุดหลายเฟรม (หน้าที่แสดงผลล่วงหน้าและหน้าที่แคชไว้) สมมติฐานที่ว่าแท็บมีเฟรมด้านนอกสุดเพียงเฟรมเดียว frameId == 0 จะยังคงแสดงเฟรมด้านนอกสุดของหน้าใช้งานอยู่ แต่เฟรมด้านนอกสุดของหน้าอื่นๆ ในแท็บเดียวกันจะไม่เท่ากับ 0 มีการเพิ่มช่อง frameType ใหม่เพื่อแก้ไขปัญหานี้ ดูส่วน "ฉันจะทราบได้อย่างไรว่าเฟรมเป็นเฟรมด้านนอกสุดหรือไม่" ของโพสต์นี้

วงจรชีวิตของเฟรมกับเอกสาร

อีกแนวคิดหนึ่งที่สร้างปัญหาให้กับส่วนขยายคือวงจรของเฟรม เฟรมโฮสต์เอกสาร (ซึ่งเชื่อมโยงกับ URL ที่คอมมิต) เอกสารเปลี่ยนแปลงได้ (เช่น โดยการไปยังส่วนต่างๆ) แต่ frameId จะไม่เปลี่ยนแปลง จึงยากที่จะเชื่อมโยงว่าบางอย่างเกิดขึ้นในเอกสารหนึ่งๆ โดยใช้เพียง frameIds เท่านั้น เราขอแนะนำแนวคิดเกี่ยวกับ documentId ซึ่งเป็นตัวระบุที่ไม่ซ้ำสำหรับเอกสารแต่ละรายการ หากมีการนำทางเฟรมและเปิดเอกสารใหม่ ตัวระบุจะเปลี่ยนแปลง ช่องนี้มีประโยชน์ในการพิจารณาว่าหน้าเว็บจะเปลี่ยนสถานะวงจรชีวิตของหน้าเมื่อใด (ระหว่างการแสดงผลล่วงหน้า/ใช้งานอยู่/แคช) เพราะหน้ายังคงเหมือนเดิม

เหตุการณ์การนำทางเว็บ

เหตุการณ์ในเนมสเปซ chrome.webNavigation สามารถเริ่มทำงานได้หลายครั้งในหน้าเดียวกัน ทั้งนี้ขึ้นอยู่กับวงจรการทำงานของเหตุการณ์นั้น ดูส่วน "ฉันจะบอกวงจรชีวิตของหน้าได้อย่างไร" และส่วน "ฉันจะทราบได้อย่างไรว่าหน้าจะเปลี่ยนไปเมื่อใด"

ฉันจะบอกวงจรชีวิตของหน้าได้อย่างไร

เราได้เพิ่มประเภท DocumentLifecycle ลงใน API ส่วนขยายหลายรายการที่ frameId เคยใช้งานได้ก่อนหน้านี้ หากมีประเภท DocumentLifecycle อยู่ในเหตุการณ์ (เช่น onCommitted) ค่าของประเภทดังกล่าวคือสถานะที่เหตุการณ์สร้างขึ้น คุณค้นหาข้อมูลจากเมธอด WebNavigation getFrame() และ getAllFrames() ได้เสมอ แต่ขอแนะนำให้ใช้ค่าจากเหตุการณ์เสมอ หากคุณใช้วิธีใดวิธีหนึ่ง โปรดทราบว่าสถานะของเฟรมอาจเปลี่ยนแปลงระหว่างเวลาที่สร้างเหตุการณ์และเวลาที่คำสัญญาส่งกลับด้วยทั้ง 2 วิธีได้รับการแก้ไข

DocumentLifecycle มีค่าต่อไปนี้

  • "prerender" : ยังไม่ได้นำเสนอต่อผู้ใช้ แต่เตรียมที่อาจจะแสดงต่อผู้ใช้
  • "active": แสดงต่อผู้ใช้ในขณะนี้
  • "cached": จัดเก็บไว้ในแคชย้อนหลัง
  • "pending_deletion": กำลังทำลายเอกสาร

ฉันจะทราบได้อย่างไรว่าเฟรมเป็นเฟรมด้านนอกสุด

ก่อนหน้านี้ส่วนขยายอาจตรวจสอบว่า frameId == 0 หรือไม่เพื่อดูว่าเหตุการณ์ที่เกิดขึ้นเป็นที่เกิดขึ้นสำหรับเฟรมด้านนอกสุดหรือไม่ การที่มีหลายหน้าในแท็บหนึ่งๆ เราจะมีเฟรมนอกสุดหลายเฟรม ดังนั้นคำจำกัดความของ frameId จึงเป็นปัญหา คุณจึงจะไม่ได้รับเหตุการณ์เกี่ยวกับเฟรม แคชย้อนหลัง อย่างไรก็ตาม สำหรับเฟรมที่แสดงผลล่วงหน้า frameId จะไม่เท่ากับ 0 สำหรับเฟรมด้านนอกสุด ดังนั้นการใช้ frameId == 0 เป็นสัญญาณเพื่อระบุว่าเป็นเฟรมด้านนอกสุดไม่ถูกต้อง

เพื่อช่วยในเรื่องนี้ เราเปิดตัวประเภทใหม่ที่เรียกว่า FrameType เพื่อให้คุณตรวจสอบว่าเฟรมเป็นเฟรมด้านนอกสุดได้ง่ายๆ หรือไม่ FrameType มีค่าต่อไปนี้

  • "outermost_frame": โดยปกติเรียกว่าเฟรมที่อยู่บนสุด โปรดทราบว่ามีตัวเลือกจำนวนมาก ตัวอย่างเช่น หากคุณมีหน้าที่แสดงผลล่วงหน้าและหน้าที่แคชไว้ แต่ละหน้าจะมีเฟรมด้านนอกสุดที่อาจเรียกว่าเฟรมระดับบนสุด
  • "fenced_frame": สงวนไว้สำหรับการใช้งานในอนาคต
  • "sub_frame": โดยปกติจะเป็น iframe

เราสามารถรวม DocumentLifecycle กับ FrameType และระบุได้ว่าเฟรมนั้นเป็นเฟรมด้านนอกสุดที่ใช้งานอยู่หรือไม่ ตัวอย่างเช่น js tab.documentLifecycle == “active” && frameType == “outermost_frame”

ฉันจะแก้ปัญหาเกี่ยวกับเวลาในการใช้งานของเฟรมได้อย่างไร

ตามที่เราได้กล่าวไว้ข้างต้นว่าเฟรมหนึ่งโฮสต์เอกสาร และเฟรมอาจนำไปยังเอกสารใหม่ แต่ frameId จะไม่เปลี่ยนแปลง ซึ่งจะสร้างปัญหาเมื่อคุณได้รับเหตุการณ์ที่มีเพียง frameId หากคุณค้นหา URL ของเฟรม สิ่งนี้อาจต่างจากตอนที่เกิดเหตุการณ์ขึ้น กรณีนี้จะเรียกว่า "ปัญหาด้านเวลาในการใช้งาน"

ในการแก้ปัญหานี้ เราได้เปิดตัว documentId (และ parentDocumentId) ตอนนี้เมธอด webNavigation.getFrame() จะทำให้ frameId เป็นตัวเลือกที่ไม่บังคับหากมี documentId documentId จะเปลี่ยนไปเมื่อมีการไปยังส่วนต่างๆ ของเฟรม

ฉันจะรู้ได้อย่างไรว่าหน้าจะเปลี่ยนเมื่อใด

มีสัญญาณที่ชัดเจนเพื่อให้ทราบว่าหน้าจะเปลี่ยนไปมาระหว่างสถานะต่างๆ หรือไม่

มาดูกันที่เหตุการณ์ WebNavigation

ในการนำทางแรกสุดของหน้า คุณจะเห็นเหตุการณ์ 4 เหตุการณ์ตามลำดับที่ระบุไว้ด้านล่าง โปรดทราบว่าทั้ง 4 เหตุการณ์อาจเกิดขึ้นโดยที่สถานะ DocumentLifecycle เป็น "prerender" หรือ "active"

onBeforeNavigate
onCommitted
onDOMContentLoaded
onCompleted

นี่เป็นภาพประกอบในแผนภาพด้านล่าง ซึ่งแสดงให้เห็นว่า documentId เปลี่ยนเป็น "xyz" เมื่อหน้าที่แสดงผลล่วงหน้ากลายเป็นหน้าที่ใช้งานอยู่

รหัสเอกสารจะเปลี่ยนแปลงเมื่อหน้าที่แสดงผลล่วงหน้ากลายเป็นหน้าที่ใช้งานอยู่
documentId จะเปลี่ยนแปลงเมื่อหน้าที่แสดงผลล่วงหน้ากลายเป็นหน้าที่ใช้งานอยู่

เมื่อหน้าเว็บเปลี่ยนจากแคชย้อนหลังหรือการแสดงผลล่วงหน้าเป็นสถานะใช้งานอยู่ จะมีเหตุการณ์อีก 3 รายการ (แต่เมื่อDocumentLifecyle เป็น "active")

onBeforeNavigate
onCommitted
onCompleted

documentId จะยังคงเหมือนเดิมในเหตุการณ์เดิม นี่เป็นภาพตัวอย่างด้านบนเมื่อเปิดใช้งาน documentId == xyz โปรดทราบว่าเหตุการณ์การนําทางเดียวกันจะเริ่มทํางาน ยกเว้นเหตุการณ์ onDOMContentLoaded เนื่องจากหน้าเว็บโหลดไปแล้ว

หากคุณมีความคิดเห็นหรือคำถามใดๆ โปรดอย่าลังเลที่จะถามที่กลุ่ม chromium-extensions