You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加页面加载监听await后Chrome扩展程序停止执行问题

Chrome扩展替换sleep为页面加载监听后陷入无限等待

我写的Chrome扩展会执行一系列操作,原本每步操作之间用sleep(1000)来等待页面完全加载。现在想把sleep替换成监听页面加载完成的逻辑,但修改后程序陷入无限等待,操作序列没法继续执行。

原代码

chrome.runtime.onMessage.addListener((message, _sender, _sendResponse) => {
    if (message.action === 'triggerAction') {
        console.log('Triggering action');
        chrome.tabs.create({ url: urlToVisit }, (tab) => {
            console.log('TAB ID: ', tab.id);
            (async function () {

                for (let action of actions) {

                    console.log('ABOUT TO EXECUTE SCRIPT', action.type);
                    chrome.scripting.executeScript(
                        {
                            target: { tabId: tab.id },
                            func: performAction,
                            args: [action]
                        }, () => {
                            console.log('Content script injected');
                        });
                    await sleep(1000); // 1 second pause

                }
                console.log('SCRIPT EXECUTED');
            })();
        })
    }
});

修改后的问题代码

chrome.runtime.onMessage.addListener((message, _sender, _sendResponse) => {
    if (message.action === 'triggerAction') {
        console.log('Triggering action');
        chrome.tabs.create({ url: urlToVisit }, (tab) => {
            console.log('TAB ID: ', tab.id);
            (async function () {

                for (let action of actions) {

                    await new Promise(resolve => {
                        chrome.scripting.executeScript(
                            {
                                target: { tabId: tab.id },
                                func: () => {
                                    window.addEventListener('DOMContentLoaded', resolve);
                                }
                            });
                    });


                    console.log('ABOUT TO EXECUTE SCRIPT', action.type);
                    chrome.scripting.executeScript(
                        {
                            target: { tabId: tab.id },
                            func: performAction,
                            args: [action]
                        }, () => {
                            console.log('Content script injected');
                        });

                }
                console.log('SCRIPT EXECUTED');
            })();
        })
    }
});

问题原因

你当前的写法有两个致命问题导致无限等待:

  1. DOMContentLoaded事件仅触发一次:如果你的操作是在同一个已加载完成的页面内执行,后续注入脚本时这个事件早就触发过了,监听永远不会生效,Promise一直处于pending状态。
  2. 上下文不匹配:注入的内容脚本里的resolve是在页面的上下文,而后台脚本里的Promise属于扩展后台上下文,两者完全隔离,根本无法触发Promise的完成逻辑。

解决方案

根据你的操作场景不同,有两种可行的解决方式:

场景1:每次操作针对新打开的页面

如果你的actions是依次在新页面执行,直接监听tabs.onUpdated事件,等待页面状态变为complete即可:

chrome.runtime.onMessage.addListener((message, _sender, _sendResponse) => {
    if (message.action === 'triggerAction') {
        console.log('Triggering action');
        chrome.tabs.create({ url: urlToVisit }, (tab) => {
            console.log('TAB ID: ', tab.id);
            (async function () {
                for (let action of actions) {
                    // 等待页面加载完成
                    await new Promise(resolve => {
                        const listener = (tabId, changeInfo) => {
                            if (tabId === tab.id && changeInfo.status === 'complete') {
                                chrome.tabs.onUpdated.removeListener(listener);
                                resolve();
                            }
                        };
                        chrome.tabs.onUpdated.addListener(listener);
                    });

                    console.log('ABOUT TO EXECUTE SCRIPT', action.type);
                    await chrome.scripting.executeScript({
                        target: { tabId: tab.id },
                        func: performAction,
                        args: [action]
                    });
                    console.log('Content script injected');
                }
                console.log('SCRIPT EXECUTED');
            })();
        })
    }
});

场景2:操作在同一个页面内执行

如果是在同一个页面内连续执行多步操作,不需要监听DOMContentLoaded,而是让内容脚本主动通知后台操作完成,或者在内容脚本内等待目标元素加载:

方案A:内容脚本执行完成后通知后台

修改performAction,操作完成后给后台发消息:

// 后台脚本
chrome.runtime.onMessage.addListener((message, _sender, _sendResponse) => {
    if (message.action === 'triggerAction') {
        console.log('Triggering action');
        chrome.tabs.create({ url: urlToVisit }, (tab) => {
            console.log('TAB ID: ', tab.id);
            (async function () {
                // 先等初始页面加载完成
                await new Promise(resolve => {
                    const listener = (tabId, changeInfo) => {
                        if (tabId === tab.id && changeInfo.status === 'complete') {
                            chrome.tabs.onUpdated.removeListener(listener);
                            resolve();
                        }
                    };
                    chrome.tabs.onUpdated.addListener(listener);
                });

                for (let action of actions) {
                    await new Promise(resolve => {
                        // 监听内容脚本的完成通知
                        const msgListener = (msg, sender) => {
                            if (sender.tab.id === tab.id && msg.action === 'actionDone') {
                                chrome.runtime.onMessage.removeListener(msgListener);
                                resolve();
                            }
                        };
                        chrome.runtime.onMessage.addListener(msgListener);

                        // 注入执行脚本
                        console.log('ABOUT TO EXECUTE SCRIPT', action.type);
                        chrome.scripting.executeScript({
                            target: { tabId: tab.id },
                            func: performAction,
                            args: [action]
                        });
                    });
                }
                console.log('SCRIPT EXECUTED');
            })();
        })
    }
});

// performAction函数
function performAction(action) {
    // 执行你的操作逻辑,比如点击、输入等
    console.log('Executing action:', action.type);
    // 操作完成后发送消息给后台
    chrome.runtime.sendMessage({ action: 'actionDone' });
}

方案B:内容脚本内等待目标元素加载

如果操作需要等待某个元素出现,直接在performAction里做等待逻辑:

// 后台脚本
chrome.runtime.onMessage.addListener((message, _sender, _sendResponse) => {
    if (message.action === 'triggerAction') {
        console.log('Triggering action');
        chrome.tabs.create({ url: urlToVisit }, (tab) => {
            console.log('TAB ID: ', tab.id);
            (async function () {
                // 等待初始页面加载完成
                await new Promise(resolve => {
                    const listener = (tabId, changeInfo) => {
                        if (tabId === tab.id && changeInfo.status === 'complete') {
                            chrome.tabs.onUpdated.removeListener(listener);
                            resolve();
                        }
                    };
                    chrome.tabs.onUpdated.addListener(listener);
                });

                for (let action of actions) {
                    console.log('ABOUT TO EXECUTE SCRIPT', action.type);
                    // 等待脚本执行完成(内部已处理元素等待)
                    await chrome.scripting.executeScript({
                        target: { tabId: tab.id },
                        func: performAction,
                        args: [action]
                    });
                    console.log('Action completed');
                }
                console.log('SCRIPT EXECUTED');
            })();
        })
    }
});

// performAction函数,内置元素等待逻辑
function performAction(action) {
    return new Promise(resolve => {
        const checkTarget = () => {
            // 假设action里包含目标元素的选择器
            const target = document.querySelector(action.selector);
            if (target) {
                // 执行操作,比如点击
                target.click();
                resolve();
            } else {
                // 每隔100ms检查一次,直到元素出现
                setTimeout(checkTarget, 100);
            }
        };
        checkTarget();
    });
}

内容的提问来源于stack exchange,提问作者Anatole Martin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 16:34:53