Chrome扩展右键菜单触发函数重复执行问题排查
Zendesk Chrome扩展右键菜单重复执行问题
问题描述
我正在开发一款面向Zendesk的Chrome扩展,核心功能之一是收集指定工单中两种格式的字符串,以摘要或「时间线」格式输出。目前功能可正常运行,但存在一个棘手bug:当选择扩展自定义右键菜单选项时,函数执行次数等于用户选择菜单前的右键点击次数。
当前实现逻辑是:运行在页面上下文的content script向background script发送消息,初始化右键菜单的onClicked监听器后,再由background向content script发送更新触发函数。曾尝试反向实现,但由于content script需要在页面上下文访问CKEditor实例,无法完成。推测每次右键点击都会将消息加入队列,选择菜单项时队列被一次性清空,导致重复执行。
相关代码
script.js(Content Script)
function generateTimeline(editingArea) { chrome.runtime.sendMessage("nmkeddobbgmklaojjmkimpaffccencgn", {operation : "UPD" }, function(response) { if(response === "UPDATED") { const editorInstance = editingArea.ckeditorInstance; const eventContainer = getEventContainer(editingArea); let dateTimeRecords = getInternalCommentTextNodes(eventContainer); dateTimeRecords.sort(dateComparator); duplicateChecker(dateTimeRecords); editorInstance.model.change(writer => { for(record of dateTimeRecords) { const paragraph = writer.createElement('paragraph'); writer.append(paragraph, editorInstance.model.document.getRoot()); const textNode = writer.createText(record.tag + ' ' + record.comment); writer.append(textNode, paragraph); } }); } }); } document.addEventListener('mouseup', function(e) { if(this.activeElement.getAttribute("role") === "textbox" && this.activeElement.getAttribute("aria-label") === "Rich Text Editor. Editing area: main") { const editingArea = singletonEventListener(this.activeElement); // 左键点击 if(e.button === 0) { createKeyPressListener(editingArea); } // 右键点击 if(e.button === 2) { generateTimeline(editingArea); } } });
background.js
const timeLineGenerator = { "id": "timeLineGenerator", "title": "Generate Timeline", "contexts":["editable"] }; chrome.runtime.onInstalled.addListener(() => { chrome.contextMenus.create(timeLineGenerator); }); function manageMenuListener(request, sender, sendResponse) { if(request.operation === "UPD") { if(chrome.contextMenus.onClicked.hasListener) { chrome.contextMenus.onClicked.removeListener(); console.log("listener removed"); } chrome.contextMenus.onClicked.addListener(() => { return sendResponse("UPDATED"); }); } } chrome.runtime.onMessageExternal.addListener(manageMenuListener);
manifest.json
{ "manifest_version": 3, "name": "Zendesk Date Time Tool", "description": "Inserts a date time string when a user defined key is pressed", "permissions":[ "scripting", "contextMenus", "activeTab", "tabs" ], "host_permissions":["<all_urls>"], "version": "1.0", "icons":{ "16":"/icons/icon16.png", "48":"/icons/icon48.png", "128":"/icons/icon128.png" }, "action": { "default_popup": "/src/index.html", "default_icon": "/icons/icon128.png" }, "background":{ "service_worker":"/src/background.js" }, "content_scripts":[{ "world": "MAIN", "matches":["https://*.zendesk.com/*"], "js":["/src/script.js"], "run_at":"document_end" }], "externally_connectable": { "matches": ["https://*.zendesk.com/*"] } }
编辑记录
- 将
return sendResponse("UPDATED");移至独立的triggerTimeline函数后,触发错误:Error in event handler: TypeError: sendResponse is not a function at triggerTimeline,修改后的background.js代码:
const timeLineGenerator = { "id": "timeLineGenerator", "title": "Generate Timeline", "contexts":["editable"] }; chrome.runtime.onInstalled.addListener(() => { chrome.contextMenus.create(timeLineGenerator); }); function triggerTimeline(request, sender, sendResponse) { return sendResponse("UPDATED"); } chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse){ if(request.operation === "UPD") { if(chrome.contextMenus.onClicked.hasListener(triggerTimeline)) { chrome.contextMenus.onClicked.removeListener(triggerTimeline); console.log("listener removed"); } chrome.contextMenus.onClicked.addListener(triggerTimeline); } });
- 使用全局函数变量存储
triggerTimeline后的background.js代码:
const timeLineGenerator = { "id": "timeLineGenerator", "title": "Generate Timeline", "contexts":["editable"] }; chrome.runtime.onInstalled.addListener(() => { chrome.contextMenus.create(timeLineGenerator); }); let triggerTimeline; chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse){ triggerTimeline = function() { return sendResponse("UPDATED"); } if(request.operation === "UPD") { if(chrome.contextMenus.onClicked.hasListener(triggerTimeline)) { chrome.contextMenus.onClicked.removeListener(triggerTimeline); console.log("listener removed"); } chrome.contextMenus.onClicked.addListener(triggerTimeline); } });
- 修改后解决了重复执行问题,但函数无法稳定触发,代码如下:
const timeLineGenerator = { "id": "timeLineGenerator", "title": "Generate Timeline", "contexts":["editable"] }; chrome.runtime.onInstalled.addListener(() => { chrome.contextMenus.create(timeLineGenerator); }); let triggerTimeline; chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse){ if(!triggerTimeline) { triggerTimeline = function() { return sendResponse("UPDATED"); } } if(request.operation === "UPD") { if(chrome.contextMenus.onClicked.hasListener(triggerTimeline)) { chrome.contextMenus.onClicked.removeListener(triggerTimeline); console.log("listener removed"); } chrome.contextMenus.onClicked.addListener(triggerTimeline); } });
内容的提问来源于stack exchange,提问作者Gnome-Improvement713
相关产品推荐
相关产品推荐

