Maison > Questions et réponses > le corps du texte
P粉0345716232023-08-25 17:51:37
Contrairement à l'API chrome.webRequest, l'API chrome.webNavigation fonctionne parfaitement car l'API chrome.webNavigation peut réveiller Service Worker, vous pouvez maintenant essayer de mettre l'API chrome.webRequest dans dans Chrome. navigation Web.
chrome.webNavigation.onBeforeNavigate.addListener(function(){ chrome.webRequest.onResponseStarted.addListener(function(details){ //............. //............. },{urls: ["*://domain/*"],types: ["main_frame"]}); },{ url: [{hostContains:"domain"}] });
P粉3863180862023-08-25 00:41:03
Description du problème
Solution :
• Exploiter
• 离屏
API
• nativeMessaging
API
• WebSocket
API
• chrome
API de messagerie
• Onglet dédié
Attention
Par définition, un Service Worker (SW) ne peut pas être persistant et le navigateur doit mettre fin de force à toutes ses activités/demandes après un certain temps, qui dans Chrome est de 5 minutes. Le minuteur d'inactivité (c'est-à-dire lorsqu'aucune activité de ce type n'est en cours) est encore plus court : 30 secondes.
L'équipeChromium considère actuellement ce comportement comme bon (l'équipe a occasionnellement assoupli certains aspects, par exemple Chrome 114 a étendu le port chrome.runtime après chaque message), mais cela ne s'applique qu'aux extensions qui observent des événements peu fréquents, ces événements sont ne s'exécute que quelques fois par jour, réduisant ainsi l'empreinte mémoire du navigateur entre les exécutions (par exemple, événements webRequest/webNavigation avec url > filtrage des sites rarement visités). Ces extensions peuvent être repensées pour conserver l'état, Exemple. Malheureusement, une telle idylle est souvent intenable.
Problème 1 : Chrome 106 et versions antérieures ne réveillent pas le logiciel pour les événements webRequest. p>
Bien que vous puissiez essayer de vous abonner à une API comme chrome.webNavigation
comme indiqué dans d'autres réponses, cela n'est utile que pour les événements qui se produisent après le démarrage du thread de travail.
Problème 2 : Le personnel arrête de se réveiller de manière aléatoire à cause d'événements.
La solutionpeut être d'appeler chrome.runtime.reload().
Problème 3 : Chrome 109 et versions antérieures ne peuvent pas prolonger le cycle de vie logiciel des nouveaux événements API chrome
à partir de scripts en arrière-plan déjà en cours d'exécution. Cela signifie que votre code ne pourra pas exécuter quoi que ce soit de manière fiable et asynchrone lorsqu'un événement se produit dans les dernières millisecondes du délai d'inactivité de 30 secondes. Cela signifie que les utilisateurs penseront que votre extension n'est pas fiable.
Question 4 : Les performances seront pires que celles de MV2 si l'extension maintient des connexions ou des états (variables) à distance qui prennent beaucoup de temps à se reconstruire, ou si vous observez des événements fréquents comme les suivants :
Lancer SW pour un nouvel événement revient essentiellement à ouvrir un nouvel onglet. Il faut environ 50 ms pour créer l'environnement, peut-être 100 ms (ou même 1 000 ms, selon la quantité de code) pour exécuter l'intégralité du script logiciel, et peut-être 1 ms (ou 1 000 ms, selon les données) pour lire le état du stockage et le reconstruire/hydrater Complexité). Même avec un script presque vide, il faut au moins 50 millisecondes, ce qui représente une surcharge considérable pour appeler un écouteur d'événement, qui ne prend que 1 milliseconde.
SW peut être redémarré des centaines de fois par jour car de tels événements sont générés en réponse aux actions de l'utilisateur avec des écarts naturels, comme cliquer sur un onglet puis écrire quelque chose, au cours duquel le logiciel est arrêté et les nouveaux événements redémarrent, consommant du CPU, du disque. , la batterie, et introduisant généralement des retards perceptibles fréquents dans la réponse de mise à l'échelle.
Chrome 110 a introduit un bug : l'appel d'une API chrome
asynchrone entraînera l'exécution du thread de travail pendant 30 secondes supplémentaires. Ce bug n'a pas encore été corrigé.
//background.js
const keepAlive = () => setInterval(chrome.runtime.getPlatformInfo, 20e3);
chrome.runtime.onStartup.addListener(keepAlive);
keepAlive();
Contributé par Kevin Augusto.
Dans Chrome 109 et versions ultérieures, vous pouvez utiliser l'API hors écran pour créer un document hors écran et envoyer des messages à partir de celui-ci toutes les 30 secondes ou moins pour que Service Worker continue de fonctionner. Actuellement, la durée de vie du document n'est pas limitée (seule la lecture audio est restreinte, que nous n'utilisons pas), mais cela pourrait changer à l'avenir.
manifest.json
"permissions": ["offscreen"]
offscreen.html
<script src="offscreen.js"></script>
offscreen.js
setInterval(async () => {
(await navigator.serviceWorker.ready).active.postMessage('keepAlive');
}, 20e3);
background.js
async function createOffscreen() {
await chrome.offscreen.createDocument({
url: 'offscreen.html',
reasons: ['BLOBS'],
justification: 'keep service worker running',
}).catch(() => {});
}
chrome.runtime.onStartup.addListener(createOffscreen);
self.onmessage = e => {}; // keepAlive
createOffscreen();
nativeMessaging
Fil de travail de service "persistant" au moment de l'hôte Dans Chrome 105 et supérieur, transmettez simplement chrome.runtime.connectNative. Si le processus hôte se termine en raison d'un crash ou d'une action de l'utilisateur, le port sera fermé et le logiciel se terminera comme d'habitude. Vous pouvez l'empêcher d'appeler à nouveau chrome.runtime.connectNative en écoutant l'événement onDisconnect du port.
Chrome 116 et versions ultérieures : échangez des messages WebSocket toutes les 30 secondes pour le maintenir en vie, par exemple une fois toutes les 25 secondes.
Inconvénients :
或 *://*/*
), qui placeront la plupart des extensions dans la lente file d'attente de révision des boutiques en ligne Attention ! Si vous disposez d'un port connecté, n'utilisez pas cette solution de contournement, utilisez une autre solution de contournement pour le port ci-dessous.
Attention ! Si vous utilisez sendMessage, vous pouvez également implémenter une solution de contournement pour sendMessage (ci-dessous).
manifest.json, parties pertinentes :
"permissions": ["scripting"],
"host_permissions": ["<all_urls>"],
"background": {"service_worker": "bg.js"}
Travailleur du service d'arrière-plan bg.js :
const onUpdate = (tabId, info, tab) => /^https?:/.test(info.url) && findTab([tab]);
findTab();
chrome.runtime.onConnect.addListener(port => {
if (port.name === 'keepAlive') {
setTimeout(() => port.disconnect(), 250e3);
port.onDisconnect.addListener(() => findTab());
}
});
async function findTab(tabs) {
if (chrome.runtime.lastError) { /* tab was closed before setTimeout ran */ }
for (const {id: tabId} of tabs || await chrome.tabs.query({url: '*://*/*'})) {
try {
await chrome.scripting.executeScript({target: {tabId}, func: connect});
chrome.tabs.onUpdated.removeListener(onUpdate);
return;
} catch (e) {}
}
chrome.tabs.onUpdated.addListener(onUpdate);
}
function connect() {
chrome.runtime.connect({name: 'keepAlive'})
.onDisconnect.addListener(connect);
}
Toutes les autres pages d'extension comme les popups ou les options :
;(function connect() {
chrome.runtime.connect({name: 'keepAlive'})
.onDisconnect.addListener(connect);
})();
Dans Chrome 99-101, vous devez toujours appeler sendResponse() dans l'écouteur chrome.runtime.onMessage même si une réponse n'est pas requise. C'est un bug dans MV3. Assurez-vous également de le faire dans les 5 minutes, sinon appelez sendResponse immédiatement et envoyez un nouveau message via chrome.tabs.sendMessage (vers l'onglet) ou chrome.runtime.sendMessage (vers la fenêtre contextuelle) lorsque le travail est terminé.
Attention ! Si vous connectez également plus de ports au service worker, vous devrez reconnecter chaque port avant que 5 minutes ne s'écoulent, par exemple dans les 295 secondes. Cela était critique dans les versions de Chrome antérieures à 104, qui tueraient le logiciel quel que soit le nombre de ports de connexion supplémentaires. Dans Chrome 104 et supérieur, ce bug est corrigé, mais vous devez quand même les reconnecter car leur cycle de vie de 5 minutes n'a pas changé, la solution la plus simple est donc de les reconnecter de la même manière dans toutes les versions de Chrome Connection : par exemple toutes les 295 secondes. .
Exemple de script backend :
chrome.runtime.onConnect.addListener(port => { if (port.name !== 'foo') return; port.onMessage.addListener(onMessage); port.onDisconnect.addListener(deleteTimer); port._timer = setTimeout(forceReconnect, 250e3, port); }); function onMessage(msg, port) { console.log('received', msg, 'from', port.sender); } function forceReconnect(port) { deleteTimer(port); port.disconnect(); } function deleteTimer(port) { if (port._timer) { clearTimeout(port._timer); delete port._timer; } }
Exemples de scripts clients, tels que les scripts de contenu :
let port;
function connect() {
port = chrome.runtime.connect({name: 'foo'});
port.onDisconnect.addListener(connect);
port.onMessage.addListener(msg => {
console.log('received', msg, 'from bg');
});
}
connect();
Au lieu d'utiliser le logiciel, ouvrez un nouvel onglet avec la page d'extension à l'intérieur, cette page agira donc comme une "page d'arrière-plan visible", c'est-à-dire que la seule chose que le logiciel doit faire est d'ouvrir cet onglet. Vous pouvez également l'ouvrir à partir de la fenêtre contextuelle d'action.
chrome.tabs.create({url: 'bg.html'})
Elle aura la même fonctionnalité que la page d'arrière-plan persistante de ManifestV2, mais a) elle sera visible et b) ne sera pas accessible via chrome.extension.getBackgroundPage
(peut être remplacée par chrome.extension.getViews).
Inconvénients :
Vous pouvez faciliter la tâche des utilisateurs en ajoutant des informations/journaux/graphiques/tableau de bord à la page, et également ajouter un beforeunload
écouteur pour éviter que l'onglet ne soit fermé accidentellement. p>
Vous devez toujours enregistrer/restaurer l'état (variables) car il n'existe pas de service worker persistant et ces solutions de contournement ont des limitations comme mentionné ci-dessus afin que le travailleur puisse être résilié. Vous pouvez conserver l'état en stockage, Exemple.
Veuillez noter que vous ne devez pas rendre vos threads de travail persistants uniquement pour simplifier la gestion des états/variables. Faites cela uniquement pour restaurer les performances qui sont détériorées par le redémarrage des threads de travail, au cas où la reconstruction de votre état serait très coûteuse ou si vous êtes accro aux événements fréquents répertoriés au début de cette réponse.