通过Google Chrome中的executeScript注入多个脚本

Dou*_*las 24 javascript google-chrome google-chrome-extension content-script

我需要以编程方式从我的Google Chrome扩展程序中将多个脚本文件(后跟代码段)注入当前页面.该chrome.tabs.executeScript方法允许单个InjectDetails对象(表示脚本文件或代码片段),以及在脚本之后执行的回调函数.目前的答案提出嵌套executeScript调用:

chrome.browserAction.onClicked.addListener(function(tab) {
    chrome.tabs.executeScript(null, { file: "jquery.js" }, function() {
        chrome.tabs.executeScript(null, { file: "master.js" }, function() {
            chrome.tabs.executeScript(null, { file: "helper.js" }, function() {
                chrome.tabs.executeScript(null, { code: "transformPage();" })
            })
        })
    })
});
Run Code Online (Sandbox Code Playgroud)

但是,回调嵌套变得难以处理.有没有办法抽象这个?

Dou*_*las 35

这是我提出的解决方案:

function executeScripts(tabId, injectDetailsArray)
{
    function createCallback(tabId, injectDetails, innerCallback) {
        return function () {
            chrome.tabs.executeScript(tabId, injectDetails, innerCallback);
        };
    }

    var callback = null;

    for (var i = injectDetailsArray.length - 1; i >= 0; --i)
        callback = createCallback(tabId, injectDetailsArray[i], callback);

    if (callback !== null)
        callback();   // execute outermost function
}
Run Code Online (Sandbox Code Playgroud)

随后,InjectDetails可以将脚本序列指定为数组:

chrome.browserAction.onClicked.addListener(function (tab) {
    executeScripts(null, [ 
        { file: "jquery.js" }, 
        { file: "master.js" },
        { file: "helper.js" },
        { code: "transformPage();" }
    ])
});
Run Code Online (Sandbox Code Playgroud)


Nin*_*ham 11

从Chrome v32开始,它支持Promise.我们应该用它来使代码干净.

这是一个例子:

new ScriptExecution(tab.id)
    .executeScripts("js/jquery.js", "js/script.js")
    .then(s => s.executeCodes('console.log("executes code...")'))
    .then(s => s.injectCss("css/style.css"))
    .then(s => console.log('done'));
Run Code Online (Sandbox Code Playgroud)

ScriptExecution 资源:

(function() {
    function ScriptExecution(tabId) {
        this.tabId = tabId;
    }

    ScriptExecution.prototype.executeScripts = function(fileArray) {
        fileArray = Array.prototype.slice.call(arguments); // ES6: Array.from(arguments)
        return Promise.all(fileArray.map(file => exeScript(this.tabId, file))).then(() => this); // 'this' will be use at next chain
    };

    ScriptExecution.prototype.executeCodes = function(fileArray) {
        fileArray = Array.prototype.slice.call(arguments);
        return Promise.all(fileArray.map(code => exeCodes(this.tabId, code))).then(() => this);
    };

    ScriptExecution.prototype.injectCss = function(fileArray) {
        fileArray = Array.prototype.slice.call(arguments);
        return Promise.all(fileArray.map(file => exeCss(this.tabId, file))).then(() => this);
    };

    function promiseTo(fn, tabId, info) {
        return new Promise(resolve => {
            fn.call(chrome.tabs, tabId, info, x => resolve());
        });
    }


    function exeScript(tabId, path) {
        let info = { file : path, runAt: 'document_end' };
        return promiseTo(chrome.tabs.executeScript, tabId, info);
    }

    function exeCodes(tabId, code) {
        let info = { code : code, runAt: 'document_end' };
        return promiseTo(chrome.tabs.executeScript, tabId, info);
    }

    function exeCss(tabId, path) {
        let info = { file : path, runAt: 'document_end' };
        return promiseTo(chrome.tabs.insertCSS, tabId, info);
    }

    window.ScriptExecution = ScriptExecution;
})()
Run Code Online (Sandbox Code Playgroud)

如果您想使用ES5,可以使用在线编译器将上述代码编译为ES5.

把我放在GitHub上:chrome-script-execution