Injecter plusieurs scripts via ExecuScript dans Google Chrome

Je dois injecter par programme plusieurs fichiers de script (suivis d'un extrait de code) dans la page actuelle de mon extension Google Chrome. La méthode chrome.tabs.executeScript permet un seul objet InjectDetails (représentant un fichier de script ou un extrait de code), ainsi qu'une fonction de rappel à exécuter après le script. Les réponses actuelles proposent des appels executeScript nidification:

 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();" }) }) }) }) }); 

Cependant, la nidification de rappel devient difficile à manier. Y a-t-il un moyen de l'extraire?

    C'est ma solution proposée:

     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 } 

    Par la suite, la séquence des scripts InjectDetails peut être spécifiée comme un tableau:

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

    Du Chrome v32, il prend en charge Promise . Nous devrions l'utiliser pour rendre le code propre.

    Voici un exemple:

     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')); 

    Source 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; })() 

    Si vous souhaitez utiliser ES5, vous pouvez utiliser le compilateur en ligne pour compiler les codes ci-dessus vers ES5.

    Prenez-moi sur GitHub: chrome-script-execution

    Compte tenu de votre réponse, je m'attendais à injecter de manière synchrone les scripts pour provoquer des problèmes (à savoir, je pensais que les scripts pourraient être chargés dans le mauvais ordre), mais cela fonctionne bien pour moi.

     var scripts = [ 'first.js', 'middle.js', 'last.js' ]; scripts.forEach(function(script) { chrome.tabs.executeScript(null, { file: script }, function(resp) { if (script!=='last.js') return; // Your callback code here }); }); 

    Cela suppose que vous ne souhaitez qu'un rappel à la fin et ne nécessitent pas les résultats de chaque script exécuté.