2016-06-02 5 views
4

Un exemple:COMMEnT setTimeout prévenir stackoverflow potentiel

var list = readHugeList(); 

var nextListItem = function() { 
    var item = list.pop(); 

    if (item) { 
     setTimeout(nextListItem, 0); 
     // ^^^^^^^^ this line 
    } 
}; 

Comment l'utilisation de setTimeout éviter stackoverflow potentiel ici? Je comprends le concept de la file d'attente d'événement aussi bien que la pile, mais j'ai du mal à relier les deux.

+4

Si vous venez d'appeler nextListItem à partir de nextListItem, la pile augmentera à chaque appel jusqu'à ce que vous atteigniez le critère de sortie (liste vide). Lorsque vous utilisez setTimeout, la fonction externe se terminera et sera supprimée de la pile, seul l'appel de fonction interne sera sur la pile alors – devnull69

Répondre

2

Le délai d'expiration défini ne provoquerait pas de dépassement de capacité de la pile, car il est asynchrone. Il va juste mettre le rappel à la file d'attente d'événements et ne pas bloquer l'exécution.

Dans le premier cas:

setTimeout met juste le rappel à la file d'attente d'événements et la fonction parent quitte après sans affairant la pile.
Même si le délai d'attente est de 0 ms, il sera appelé dans la prochaine boucle d'événement, donc pas bloquer le code dans l'exécution

var nextListItem = function() { 
    var item = list.pop(); 

    if (item) { 
     setTimeout(nextListItem, 0); 
    } 
}; 

Dans le second cas:

Parent appeler la fonction de l'enfant en mettant nouvelle entrée dans la pile, même si les parents ne sont pas effacés de la pile.
Finalement, plus d'appels récursifs pourraient faire sauter la pile.

var nextListItem = function() { 
     var item = list.pop(); 

     if (item) {   
      nextListItem(); 
     } 
    }; 
1

Pensez à setTimeout(, 0) pour planifier une fonction à exécuter après la fin de celle-ci. nextListItem() ne sera pas appelée récursivement, mais appelée à nouveau par l'environnement JS.

Si vous faites var r() = function() { r(); }; la fonction appelle lui-même et débordera la pile. Si vous faites var r() = function() { setTimeout(r, 0); }; alors r() sera programmé pour s'exécuter après r() se termine et il fonctionnera pour toujours.

La raison est d'utiliser setTimeout(, 0) au lieu de while ou for pour faire une boucle sur la liste. Il permet au navigateur de traiter d'autres événements avant le prochain appel à nextListItem. Si la liste est longue, cela évite de bloquer le navigateur pendant longtemps. D'un autre côté, si nextListItem manipule le DOM, c'est beaucoup plus lent que de le faire en une seule fois.