2010-09-17 5 views
0

J'ai un script greasemonkey qui, lorsqu'il est exécuté, vérifie si une mise à jour est disponible et invite l'utilisateur à télécharger la mise à jour si c'est le cas. Cela fonctionne normalement, sauf que si un utilisateur ouvre plusieurs onglets simultanément (par exemple, en démarrant le navigateur, ou en utilisant "Ouvrir tout dans les onglets" pour un dossier de signets), le script greasemonkey pingera l'utilisateur dans chaque onglet simultanément, ce qui est un peu d'un PITA pour un utilisateur.Implémentation d'un verrou à l'aide de GM_getValue GM_setValue

Je pense que le seul canal de communication que j'ai entre les instances du script est GM_setValue/GM_getValue, ce qui permet aux instances d'accéder à un stockage clé/valeur.

Ce que je dois faire est de trouver un système de verrouillage (appelons-le GM_setLock/GM_releaseLock), donc je peux faire ce qui suit:

GM_setLock(); 
const tried_update = GM_getValue(available_version); 
GM_setValue(available_version, true); 
GM_releaseLock(); 

if (!tried_update) { prompt_user() } 

Sans le verrouillage je pouvais avoir plusieurs instances dans différents onglets tous ont lu GM_getValue(available_version) avant que l'un d'eux n'atteigne GM_setValue(available_version, true), de sorte que l'utilisateur puisse être interrogé plusieurs fois. La chose est, je ne sais pas comment mettre en œuvre le verrouillage de la tête si je n'ai accès qu'à (ce que je veux prétendre être) une lecture atomique et une opération d'écriture atomique (et non écrire atomique et retourner la valeur précédente). Des idées?

Répondre

1

Vous ne pouvez pas tout à fait le faire avec cette syntaxe dans Greasemonkey, mais quelque chose comme cela devrait faire ce que vous voulez:

Wrap la vérification de mise à niveau (ou autre), comme ceci:

function UpgradeCheckFunction() 
{ 
    //--- Put payload code here. 

    alert ("I just ran an an upgrade check?!"); 
} 

.
Définissez ensuite PerformOnceAcrossTabs(), comme ceci:

function PerformOnceAcrossTabs (sName, oFunction) 
{ 
    var OldValue = GM_getValue (sName); 
    if (OldValue) 
    { 
     //--- Optionally also do a timestamp check and clear any "locks" that are X hours old. 
     return; 
    } 

    GM_setValue (sName, new Date().toString()); 

    //--- run payload function here. 
    (oFunction)(); 

    //--- Clear "Lock". 
    GM_deleteValue (sName); 
} 

.
appeler ensuite comme si:

PerformOnceAcrossTabs ("UpgradeCheckLock", UpgradeCheckFunction); 
+0

Je me sens comme celui-ci est proche (et peut-être il est aussi proche que vous pouvez obtenir avec les outils Greasemonkey fournit), mais il est encore vulnérable à plusieurs onglets en cours d'exécution de la charge utile en même temps. Appelons tout dans 'PerformOnceAcrossTabs' avant la partie' GM_setValue' (1), et tout le reste partie (2). Si nous avons deux onglets ou plus exécutant 'PerformOnceAcrossTabs', alors chaque fois que nous aurons deux onglets ou plus complétez la partie (1) avant toute partie de début (2), alors nous aurons plusieurs onglets exécutant la fonction de charge utile. – rampion

+1

@rampion: J'ai testé cela dans des dizaines d'onglets simultanés et je n'ai encore rien vu d'autre qu'un fonctionnement sans faille. Alors qu'un extrême-bord, une condition de course, comme vous le décrivez, est possible: (1) Je dois encore être en mesure de le déclencher (2) et alors? Dans le pire des cas, vous recevez 2 alertes au lieu des 50 précédentes ou du 1 souhaité. (3) Étant donné que Firefox est monothread, je suspecte que la condition de concurrence risque de ne jamais se déclencher dans ce navigateur. Vous êtes beaucoup plus susceptible de problèmes de verrous stale - de pages écrasées, etc. C'est pourquoi la vérification de l'horodatage est suggéré. –

Questions connexes