2009-01-09 5 views
1

J'appelle une fonction javascript qui définit l'opacité d'un iframe un nombre inconnu de fois en succession rapide. Fondamentalement, ce interpole l'alpha de 0 à 100. voici le codejavascript race condition


    function setAlpha(value) 
    { 
     iframe.style.opacity = value * .01; 
     iframe.style.filter = 'alpha(opacity =' + val + ')'; 
    } 

Mon problème est que pour la première fois, il travaille dans ie (7) et non dans Firefox (3,02). dans Firefox je reçois un délai et puis le contentdocument apparaît avec une opacité de 100. Si je colle une alerte dedans ça fonctionne, donc je devine que c'est une condition de course (bien que je pensais que javascript était single threaded) et que la fonction setAlpha est appelé avant la fin de l'exécution de la dernière fonction. Toute aide serait grandement appréciée. J'ai lu le message "Éviter un post de course javascript" mais je pense que cela se qualifie comme quelque chose de différent (en plus je ne peux pas comprendre comment appliquer cet exemple à celui-ci).

+0

Pouvez-vous fournir plus d'informations sur la manière dont vous appelez cette fonction en boucle? – Rob

Répondre

1

Javascript ne fonctionne pas sur plusieurs threads, donc vous êtes à l'abri des conditions de course (en ignorant la prise en charge des threads de Worker dans Safari et Firefox: D). Simple question, comment appeler setAlpha plusieurs fois, firefox, safari et opera toutes les mises à jour de feuille de style coalesce - par exemple. ils ne vont pas repeindre ou même recalculer les informations de style pendant que js est en cours d'exécution à moins qu'ils ne le fassent. Donc, ils ne peindront que si JS a terminé.

Donc, si vous faites

while(...) setAlpha(...) 

ils ne seront pas à jour, vous aurez probablement besoin d'utiliser setTimeout pour déclencher plusieurs appels distincts à mettre à jour le style.

Une alternative serait d'utiliser une bibliothèque telle que jQuery, mootools, etc. que je rappelle vaguement fournir un mécanisme simplifié pour faire ces types d'animations et de transitions. En prime je crois au moins quelques bibliothèques utiliseront aussi des règles CSS de transition webkit et animation lorsqu'ils sont disponibles (par exemple Safari, et je pense le dernier Firefox construit.)

[edit: mise en garde: i haen't effectivement utilisé l'une de ces bibliothèques, je ne lis que ce qu'ils sont censés faire. Mes sites rendent la même chose dans Lynx que n'importe quel autre navigateur parce que je ne pouvais pas me sortir d'un sac en papier: D]

0

Certains navigateurs sont assez intelligents pour retarder les changements dans le DOM jusqu'à ce que la pile d'appels soit vide.

C'est une chose généralement intelligente à faire. Par exemple, si vous appelez une fonction qui change un élément en jaune et que vous appelez immédiatement une fonction qui ramène le même élément à son état d'origine, le navigateur ne devrait pas perdre de temps à effectuer le changement, car cela devrait arriver si rapidement être imperceptible à un utilisateur.

L'astuce setTimeout(func, 0) est généralement utilisée pour forcer Javascript à retarder l'exécution de func jusqu'à ce que la pile d'appels soit vide.

Dans le code:

function setAlpha(opacity){ 
    some_element.style.opacity = opacity; 
} 

/** 
* This WON'T work, because the browsers won't bother reflecting the 
* changes to the element's opacity until the call stack is empty, 
* which can't happen until fadeOut() returns (at the earliest) 
**/ 
function fadeOut(){ 
    for (var i=0; i<10; i++){ 
     setAlpha(0.1*i);  
    } 
} 

/** 
* This works, because the call stack will be empty between calls 
* to setAlpha() 
**/ 
function fadeOut2(){ 
    var opacity = 1; 
    setTimeout(function setAlphaStep(){ 
     setAlpha(opacity); 
     if (opacity > 0){ 
      setTimeout(setAlphaStep, 10);   
     } 
     opacity -= 0.1; 
    }, 0); 
} 

Tout cela se résume à être une excuse merveilleuse d'utiliser l'une des nombreuses bibliothèques javascript qui gèrent ce genre de choses difficiles pour vous.

Edit: et voici un good article on the tricky Javascript call stack

0

Utilisez-vous setTimeout ou une boucle serrée? Si vous utilisez simplement une boucle pour appeler la fonction, passez à l'utilisation de setTimout.

exemple:

function setAlpha(value) 
    { 
     iframe.style.opacity = value * .01; 
     iframe.style.filter = 'alpha(opacity =' + val + ')'; 
     if(value < 100) { 
     setTimeout(function() {setAlpha(value+1)},20); 
     } 
    } 
    setAlpha(0); 

Parce que vous voyez, ce n'est pas seulement le javascript qui est seul thread. C'est l'ensemble du navigateur. Si votre javascript va dans un looploop, vous suspendez l'ensemble du navigateur. Ainsi, le navigateur s'arrête en attente de la fin du javascript et n'a même pas la possibilité de mettre à jour l'écran, alors que votre code change rapidement certaines valeurs dom.

5

Le problème est que la plupart des navigateurs ne sont pas repeints tant qu'il n'y a pas de pause dans l'exécution de javascript.

Cela peut être résolu en utilisant setTimeout, comme d'autres l'ont suggéré. Cependant, je recommande d'utiliser quelque chose comme jQuery, ou l'une des bibliothèques javascript pour faire des animations. L'exécution de setTimeout 100 fois est une mauvaise idée car la durée de l'animation varie en fonction du navigateur et de la vitesse de l'ordinateur de l'utilisateur. La bonne façon de faire des animations est de spécifier combien de temps elles dureront et de vérifier l'heure du système pour déterminer jusqu'où l'animation doit progresser. [Edit:] Le code ci-dessus est seulement pour illustrer comment faire des animations basées sur l'horloge du système au lieu de simples intervalles. S'il vous plaît utiliser une bibliothèque pour faire des animations. Le code ci-dessus ne fonctionnera pas sur IE, car IE utilise "filter: opacity (xx)" au lieu de "opacity". Les bibliothèques s'en occuperont pour vous et fourniront également de belles fonctionnalités telles que des événements d'achèvement et la possibilité d'annuler l'animation.

Questions connexes