javascript - ตัวฟังเหตุการณ์ของส่วนขยาย Chrome V3 หยุดทำงานหลังจากหลายวัน
ฉันกำลังพัฒนาส่วนขยายของ Chrome และสังเกตว่าส่วนขยายของฉันทำงานได้ดีเป็นเวลาหลายวันหรือมากกว่า แต่สุดท้ายก็ถึงจุดที่ตัวฟังเหตุการณ์ต่างๆ ดูเหมือนจะหยุดทำงาน ตัวอย่างเช่น ส่วนขยายของฉันฟังการอัปเดตข้อมูลจาก popup ของมันและยังฟังการแจ้งเตือนที่ถูกกระตุ้นทุกนาที แต่ในบางจุดทั้งสองอย่างนี้ดูเหมือนจะหยุดทำงานพร้อมกัน ตัวฟังเหตุการณ์ของฉันถูกลงทะเบียนแบบซิงโครนัสเท่าที่ฉันสามารถบอกได้ และพวกมันยังคงทำงานได้นานกว่าที่ฉันคาดว่าจะเป็นถ้าไม่ใช่กรณีนี้
นอกจากนี้ เมื่อส่วนขยายถึงสถานะนี้ ฉันพบว่าเมื่อฉันเพิ่มตัวฟังเหตุการณ์ทดสอบในคอนโซลของ service worker ตัวฟังเหล่านี้ก็ไม่ได้ทำงานอย่างถูกต้องเช่นกัน
ฉันยังไม่สามารถระบุสถานการณ์ที่แน่นอนที่เกิดปัญหานี้ได้ หรือทำให้มันเกิดซ้ำได้สำเร็จ ยกเว้นโดยการรอหลายวันในขณะที่ส่วนขยายของฉันกำลังทำงาน ปัญหาไม่ปรากฏว่ามีความเกี่ยวข้องกับข้อยกเว้นระหว่างรันไทม์ใด ๆ หากมีใครเคยประสบปัญหาแบบเดียวกันหรือมีคำแนะนำในการดีบัก ฉันจะขอบคุณอย่างมาก ณ ตอนนี้ ฉันไม่แน่ใจว่าจะดำเนินการสอบสวนปัญหานี้ต่อไปอย่างไร
คำตอบ #1
ฉันได้ต่อสู้กับปัญหานี้เมื่อไม่นานมานี้และได้เห็นคำถามนี้ถูกโพสต์หลายครั้งโดยมีคำตอบหรือการสนับสนุนน้อยมาก ฉันต้องการให้ข้อเสนอแนะเกี่ยวกับสิ่งที่ฉันค้นพบในการสืบสวนของฉัน และบางทีอาจจะเป็นประโยชน์กับคุณ
พื้นหลัง:
ไม่กี่เดือนที่ผ่านมา เราเริ่มได้รับข้อร้องเรียนเป็นครั้งคราวจากผู้ใช้บางคนว่าตัวขยาย Chrome ไม่ทำงานอีกต่อไป โดยพื้นฐานแล้ว ปุ่มไม่ได้ถูกแทรกลงในหน้าเว็บของพวกเขาตามที่คาดไว้ ผู้ใช้สามารถเข้าสู่ระบบระบบของเราจากไอคอนตัวขยายได้ แต่ไม่ได้กระตุ้นให้สคริปต์ทำงานในแท็บ วิธีเดียวที่จะแก้ปัญหาคือการรีสตาร์ทเบราว์เซอร์หรือคอมพิวเตอร์
ส่วนขยายได้ลงทะเบียนการแจ้งเตือนหลายรายการ ตัวฟัง onTabUpdate และตัวฟัง onMessage แต่ไม่มีตัวใดตอบสนอง แม้กระทั่งเมื่อเปิด devtools ฉันก็ไม่สามารถทำการใด ๆ ได้ เช่น ส่งข้อความ หรือแม้แต่เรียกใช้ chrome.runtime.reload() และไม่มีบันทึกปรากฏขึ้น
ข้อสังเกตสำคัญสองสามข้อ:
- ปัญหาจะปรากฏหลังจากใช้งานไปไม่กี่วันโดยไม่มีปัญหา
- ไม่ใช่ผู้ใช้ทุกคนที่ประสบปัญหา
- มันเกิดขึ้นในหลายเวอร์ชันของส่วนขยาย
การสอบสวน:
โดยการใช้ chrome://serviceworker-internals ผมสามารถระบุได้ว่าในพฤติกรรมปกติ ส่วนขยายจะเข้าสู่สถานะ RUNNING เมื่อมีการทริกเกอร์ของการแจ้งเตือนหรือเมื่อมีการเปลี่ยน/เปิดแท็บ และหลังจากไม่มีการใช้งาน 30 วินาที ส่วนขยายจะเปลี่ยนไปเป็นสถานะ STOPPED แต่จะกลับเข้าสู่สถานะ RUNNING เมื่อมีเหตุการณ์หรือข้อความเกิดขึ้น
ผลการค้นพบ:
เนื่องจากฉันไม่สามารถทำให้ปัญหาเกิดขึ้นซ้ำได้ด้วยตัวเอง ฉันจึงไม่สามารถยืนยันได้ว่าสิ่งนี้จะแก้ไขสถานการณ์ของเราได้ แต่ก็อาจช่วยคุณในสถานการณ์ของคุณได้
ฉันพบสิ่งสำคัญ 2 อย่างในโค้ดของฉันที่อาจช่วยตรงนี้ได้:
ในการออกจากระบบจากระบบของฉัน สคริปต์พื้นหลังจะส่งข้อความที่สคริปต์ส่วนหน้าได้ฟังอยู่ เพื่อส่งข้อความนี้ ฉันได้รันการค้นหาแท็บบนแท็บทั้งหมด
chrome.tabs.query({ status: 'complete' }, (tabs) => {
tabs.forEach((tab) => {
chrome.tabs.sendMessage(tab.id, { event: 'logout', data: {} }, () => {});
});
});
- ปัญหาแรกในโค้ดของฉัน คือฉันไม่เคยเรียกใช้
sendResponse()(ฉันแค่สมมติว่าฉันไม่จำเป็นต้องใช้มัน แล้วจะเรียกทำไม) แม้ว่าonMessageจะมีreturn Trueโค้ดคาดหวังการตอบกลับแบบอะซิงโครนัส แต่ไม่เคยได้รับ และจะเกิดข้อผิดพลาด:
Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received
ข้อผิดพลาดนี้ดูเหมือนไม่ส่งผลกระทบจริงต่อเวลารันหรือพฤติกรรมของโค้ดของฉัน และฉันก็ไม่สามารถหาสาเหตุได้ ดังนั้นฉันจึงละเลยมัน
- ปัญหาที่สองดูเหมือนจะเกิดจากการที่คำสืบค้นแท็บถูกใช้กับแท็บทั้งหมด ในไฟล์ manifest ของฉันฉันจำกัดส่วนขยายของฉันให้ใช้กับเว็บไซต์บางเว็บไซต์เท่านั้น ซึ่งส่งผลให้เกิดข้อผิดพลาดที่สอง:
uncaught (in promise) error: could not establish connection. receiving end does not exist.
ข้อผิดพลาดทั้งสองนี้ใช้เวลาพอสมควรในการแก้ไข (ระยะเวลาหมดเวลาประมาณ 60 วินาที) และในช่วงเวลานั้น ส่วนขยายจะยังคงอยู่ในสถานะกำลังทำงาน หากผู้ใช้เปิดแท็บหลายแท็บ (เหมือนกับที่คนส่วนใหญ่ทำกัน) ส่วนขยายก็จะติดอยู่ในสถานะกำลังทำงานอย่างต่อเนื่องในที่สุด
การดำเนินการที่ดำเนินไปแล้ว
ที่นี่ ผมไม่ค่อยแน่ใจว่าเกิดอะไรขึ้น (ว่ามีบั๊กใน Chrome หรือไม่) แต่ดูเหมือนว่าหลังจากเวลาผ่านไป X ระยะ ตัวฟัง API ของ Chrome จะหยุดตอบสนอง เนื่องจากส่วนขยายไม่เคยหยุดและรีสตาร์ท ตัวฟังจึงไม่มีการกู้คืน และสคริปต์พื้นหลังจะติดอยู่ในสถานะนี้ตลอดไป ไอคอนของส่วนขยายใช้งานได้ไม่มีปัญหา แต่สคริปต์หลักไม่เคยถูกเรียกใช้งาน มีเพียงการรีสตาร์ท Chrome หรือคอมพิวเตอร์เท่านั้นที่ดูเหมือนจะแก้ปัญหานี้ได้
ฉันแก้ปัญหา 2 เรื่องโดยการเรียก sendMessage() ในทุกที่ที่ฉันมีตัวฟัง onMessage และโดยการเปลี่ยนการค้นหาแท็บเป็น <all_urls> ซึ่งจำกัดการค้นหาให้กับแท็บที่ตรงกับ URL ใน manifest ซึ่งทำให้ข้อผิดพลาดทั้ง 2 หายไป ผลลัพธ์คือ ส่วนเสริมดูเหมือนจะกลับไปสู่รอบการทำงาน/ไม่ทำงานของสคริปต์เบื้องหลัง ทุกครั้งที่ตื่นขึ้น สคริปต์เบื้องหลังจะทำงาน รีเซ็ตการเตือนตามความจำเป็น และรีเซ็ตตัวฟัง
หวังว่าสิ่งนี้จะช่วยในสถานการณ์นี้ได้ โชคดีนะ!
คำตอบ #2
ฉันกำลังดิ้นรนกับปัญหาเดียวกันและค้นหาคำตอบทางอินเทอร์เน็ตแต่ไม่พบ แต่ในที่สุดฉันสามารถแก้ไขมันได้โดยบังเอิญ
วิธีแก้ไขที่ช่วยฉันได้คือการย้ายการกำหนดตัวฟังทั้งหมดจากฟังก์ชันขึ้นไปที่สตรีมหลัก
ก่อน:
chrome.runtime.onStartup.addListener(Init);
async function Init() {
...
chrome.tabs.onActivated.addListener(__listener__);
...
}
หลังจาก:
chrome.runtime.onStartup.addListener(Init);
chrome.tabs.onActivated.addListener(__listener__);
async function Init() {
...
}
ผมสมมติว่า ด้วยเหตุผลบางประการ การกระทำทั้งหมด กระบวนการ ตัวแปร (ที่อยู่ของพวกมัน) และการจัดสรรหน่วยความจำอื่นใดที่ดำเนินการในฟังก์ชัน จะถูกล้างออกเมื่อส่วนขยายถูกพักการทำงาน ถ้าผมถูกต้อง นี่จะทำให้อีเวนต์พยายามเรียกใช้งานลิสเทนเนอร์ที่ไม่มีอยู่ในหน่วยความจำแล้ว
