Comprendre les fermetures de javascript et l'utilisation de la mémoire

EDIT : Ce n'est qu'un exemple simple pour démêler la préoccupation que j'ai avec un programme beaucoup plus vaste. Je n'utiliserais pas ce code réel pour quelque chose 🙂

Si je l'exécute –

<!DOCTYPE html> <html> <head> <script> function update(amount, win, data) { win.innerText = 'Count is ' + amount; setTimeout(function() { update(amount + 1, win, {data: 'something'})}, 1000); } window.onload = function() { var win = document.getElementById('item'); update(0, win, 0); } </script> </head> <body> <div id="item"></div> </body> </html> 

L'appel à SetTimeout crée vraisemblablement une fermeture qui capture le contenu des paramètres à la fonction "mise à jour" (montant, gain, données). Donc, ces variables sont conservées en mémoire jusqu'à ce que le délai d'attente soit appelé et retourne afin qu'ils soient disponibles à l'intérieur de cette fonction appel …

Mais cette fonction crée une nouvelle fermeture pour la prochaine itération du délai d'attente … Qu'est-ce qui sera capturé dans cette deuxième fermeture? Est-ce seulement les nouvelles copies de ces variables ou ceux qui ont-ils fait partie de l'appel de fonction seront-ils capturés à nouveau dans la nouvelle fermeture?

Fondamentalement, cela finira-t-il par manque de mémoire en raison du fait que les données de chaque fermeture deviennent de plus en plus grandes, ou est-ce sûr et raisonnable?

Selon moi, lorsqu'une fermeture est créée, le contexte lexical actuel est regroupé avec elle. Dans votre cas, ce serait le amount, win, data .

Ce contexte sera utilisé, lorsque le délai d'extinction se déclenche, pour exécuter la fermeture et ainsi appeler à nouveau la update la fonction; Cet appel, bien qu'il apparaisse ainsi, n'est pas récursif, car l'exécution précédente de la update déjà terminée et son contexte d'origine (dynamique, différent de celui du lexical) a déjà été libéré. (Je pense que cela est important à noter, car il semble que vous vous inquiétez d'une sorte de croissance de la pile en raison de la récurrence).

Donc, encore une fois, la update est exécutée une deuxième fois encore, un délai est défini et une fermeture créée. Cette fermeture est regroupée avec le contexte actuel de l'exécution lexique (qui inclut uniquement le amount, win, data ) et programmé avec la minuterie. La update termine et la supprime de la pile. Encore une fois, la minuterie se déclenche et la mise à jour est appelée à nouveau …

Donc, vous ne devriez pas vous soucier d'une croissance illimitée du contexte, pour deux raisons: premièrement, seul le contexte lexical est regroupé avec la fermeture; L'appel n'est pas récursif.

Une nouvelle fermeture est créée chaque fois que le délai d'appel est appelé, comme vous l'avez dit correctement. Mais une fois que le rappel a été exécuté, il n'y a plus de référence à la fermeture précédente, de sorte qu'il peut être récupéré.