web-dev-qa-db-fra.com

La taille maximale de la pile d'appels a dépassé l'erreur

J'utilise un fichier de bibliothèque JavaScript Direct Web Remoting (DWR) et j'obtiens une erreur uniquement dans Safari (ordinateur de bureau et iPad)

Ça dit 

Taille de la pile d'appel maximale dépassée.

Qu'est-ce que cette erreur signifie exactement et arrête-t-elle complètement le traitement?

De plus, tout correctif pour le navigateur Safari (En fait, sur le iPad Safari, il est indiqué 

JS: délai dépassé

que je suppose est le même problème de pile d'appel)

404
testndtv

Cela signifie que quelque part dans votre code, vous appelez une fonction qui à son tour appelle une autre fonction, et ainsi de suite, jusqu'à atteindre la limite de la pile d'appels.

C'est presque toujours à cause d'une fonction récursive avec un cas de base qui n'est pas respecté.

Voir la pile

Considérez ce code ...

(function a() {
    a();
})();

Voici la pile après une poignée d'appels ...

Web Inspector

Comme vous pouvez le constater, la pile d'appels augmente jusqu'à atteindre une limite: la taille de la pile codée en dur du navigateur ou l'épuisement de la mémoire.

Pour résoudre ce problème, assurez-vous que votre fonction récursive a un scénario de base qui peut être satisfait ...

(function a(x) {
    // The following condition 
    // is the base case.
    if ( ! x) {
        return;
    }
    a(--x);
})(10);
494
alex

Vous pouvez parfois l'obtenir si vous importez/intégrez par mégarde deux fois le même fichier JS. Cela vaut la peine de vérifier dans l'onglet Ressources de l'inspecteur :)

73
lucygenik

Dans mon cas, j'envoyais des éléments d'entrée à la place de leurs valeurs:

$.post( '',{ registerName: $('#registerName') } )

Au lieu de:

$.post( '',{ registerName: $('#registerName').val() } )

Cela a gelé mon onglet Chrome à un point tel qu'il ne m'avait même pas montré la boîte de dialogue "Attendre/Tuer" lorsque la page ne répondait plus ...

34
FKasa

Il y a une boucle récursive quelque part dans votre code (c'est-à-dire une fonction qui s'appelle finalement elle-même encore et encore jusqu'à ce que la pile soit pleine).

Les autres navigateurs ont soit de plus grandes piles (donc vous obtenez un délai d’attente), soit ils avalent l’erreur pour une raison quelconque (peut-être un try-catch mal placé).

Utilisez le débogueur pour vérifier la pile d'appels lorsque l'erreur se produit.

25
Aaron Digulla

Dans mon cas, je convertissais un tableau d'octets volumineux en une chaîne en utilisant les éléments suivants:

String.fromCharCode.apply(null, new Uint16Array(bytes))

bytes contient plusieurs millions d'entrées, ce qui est trop volumineux pour tenir sur la pile.

11
Nate Glenn

Le problème avec la détection des flux de pile de recouvrement est parfois que la trace de la pile va se dérouler et que vous ne pourrez pas voir ce qui se passe réellement.

Certains outils de débogage plus récents de Chrome ont été utiles à cet égard.

Appuyez sur le Performance tab, assurez-vous que Javascript samples est activé et vous obtiendrez un résultat similaire.

Il est assez évident que le débordement est ici! Si vous cliquez sur extendObject, vous pourrez voir le numéro de ligne exact dans le code. 

 enter image description here

Vous pouvez également voir les horaires qui peuvent ou ne pas être utiles ou un hareng rouge.

 enter image description here


Une autre astuce utile si vous ne trouvez pas le problème est de placer de nombreuses instructions console.log à l'endroit où vous pensez que le problème se trouve. L'étape précédente ci-dessus peut vous aider.

Dans Chrome, si vous produisez de manière répétée des données identiques, celles-ci s'affichent ainsi, montrant ainsi le problème plus clairement. Dans ce cas, la pile a atteint 7152 images avant son crash final:

 enter image description here

9
Simon_Weaver

Si vous avez besoin d'un processus/récursion infini pour une raison quelconque, vous pouvez utiliser un outil Web dans un thread séparé . http://www.html5rocks.com/fr/tutorials/workers/basics/

si vous souhaitez manipuler des éléments dom et les redessiner, utilisez animation http://creativejs.com/resources/requestanimationframe/

5
Dr. Dama

Vérifiez les détails de l'erreur dans la console de la barre d'outils de développement Chrome. Cela vous donnera les fonctions de la pile d'appels et vous guidera vers la récursion qui cause l'erreur.

5
chim

Dans mon cas, l'événement click se propageait sur l'élément enfant. Donc, je devais mettre ce qui suit:

e.stopPropagation ()

sur l'événement de clic:

 $(document).on("click", ".remove-discount-button", function (e) {
           e.stopPropagation();
           //some code
        });
 $(document).on("click", ".current-code", function () {
     $('.remove-discount-button').trigger("click");
 });

Voici le code html:

 <div class="current-code">                                      
      <input type="submit" name="removediscountcouponcode" value="
title="Remove" class="remove-discount-button">
   </div>
5
Shahdat

Dans mon cas, deux modaux jQuery étaient empilés l'un sur l'autre. Prévenir cela a résolu mon problème. 

2
Barry Guvenkaya

Cela peut également provoquer une erreur Maximum call stack size exceeded:

var items = [];
[].Push.apply(items, new Array(1000000)); //Bad

Pareil ici:

items.Push(...new Array(1000000)); //Bad

De la Mozilla Docs :

Mais attention: en appliquant de cette manière, vous courez le risque de dépasser la limite de longueur d'argument du moteur JavaScript. Les conséquences de l'application d'une fonction avec trop d'arguments (pensez plus de dizaines de milliers d'arguments) varient d'un moteur à l'autre (JavaScriptCore a une limite d'arguments codée en dur de 65536), car la limite (même la nature de toute pile trop grande comportement) n'est pas spécifié. Certains moteurs lanceront une exception. Plus pernicieusement, d'autres limiteront arbitrairement le nombre d'arguments réellement passés à la fonction appliquée. Pour illustrer ce dernier cas: si un tel moteur avait une limite de quatre arguments (les limites réelles sont bien entendu nettement plus élevées), ce serait comme si les arguments 5, 6, 2, 3 avaient été passés pour s'appliquer dans les exemples ci-dessus, plutôt que le tableau complet.

Alors essayez:

var items = [];
var newItems = new Array(1000000);
for(var i = 0; i < newItems.length; i++){
  items.Push(newItems[i]);
}
1
bendytree

Vérifiez si vous avez une fonction qui s'appelle elle-même. Par exemple 

export default class DateUtils {
  static now = (): Date => {
    return DateUtils.now()
  }
}
0
onmyway133

Presque chaque réponse ici indique que cela ne peut être causé que par une boucle infinie. Ce n'est pas vrai, sinon vous pourriez surcharger la pile d'appels profondément imbriqués (pour ne pas dire que c'est efficace, mais c'est certainement possible). Si vous avez le contrôle de votre machine virtuelle JavaScript, vous pouvez ajuster la taille de la pile. Par exemple:

node --stack-size=2000

Voir aussi: Comment puis-je augmenter la taille maximale de la pile d'appels dans Node.js

0
ghayes

Ont découvert le même problème, je ne pouvais pas comprendre ce qui n'allait pas, blâmant Babel;)

Avoir du code ne renvoyant aucune exception dans les navigateurs:

if (typeof document.body.onpointerdown !== ('undefined' || null)) {

problème a été mal créé || (ou) partie comme babel crée sa propre vérification de type:

function _typeof(obj){if(typeof Symbol==="function"&&_typeof(Symbol.iterator)==="symbol")

donc enlever

|| null

fait la transpilation babel a travaillé.

0
Raphael

Si vous travaillez avec Google Maps, vérifiez si les dernières données sont passées au format new google.maps.LatLng. Dans mon cas, ils ont été passés comme indéfinis. 

0
User-8017771

J'ai eu cette erreur parce que j'avais deux fonctions JS avec le même nom

0
iceDragon

vous pouvez trouver votre fonction récursive dans le navigateur Chrome, appuyez sur ctrl + shift + j, puis sur l'onglet source, ce qui vous donne un flux de compilation de code et vous pouvez le trouver en utilisant un point d'arrêt dans le code.

0
Vishal Patel

J'ai également fait face à un problème similaire ici est les détails lors du téléchargement du logo à l'aide de la liste déroulante d'envoi de logo

<div>
      <div class="uploader greyLogoBox" id="uploader" flex="64" onclick="$('#filePhoto').click()">
        <img id="imageBox" src="{{ $ctrl.companyLogoUrl }}" alt=""/>
        <input type="file" name="userprofile_picture"  id="filePhoto" ngf-select="$ctrl.createUploadLogoRequest()"/>
        <md-icon ng-if="!$ctrl.isLogoPresent" class="upload-icon" md-font-set="material-icons">cloud_upload</md-icon>
        <div ng-if="!$ctrl.isLogoPresent" class="text">Drag and drop a file here, or click to upload</div>
      </div>
      <script type="text/javascript">
          var imageLoader = document.getElementById('filePhoto');
          imageLoader.addEventListener('change', handleImage, false);

          function handleImage(e) {
              var reader = new FileReader();
              reader.onload = function (event) {

                  $('.uploader img').attr('src',event.target.result);
              }
              reader.readAsDataURL(e.target.files[0]);
          }
      </script>
      </div>

CSS.css

.uploader {
  position:relative;
  overflow:hidden;
  height:100px;
  max-width: 75%;
  margin: auto;
  text-align: center;

  img{
    max-width: 464px;
    max-height: 100px;
    z-index:1;
    border:none;
  }

  .drag-drop-zone {
    background: rgba(0, 0, 0, 0.04);
    border: 1px solid rgba(0, 0, 0, 0.12);
    padding: 32px;
  }
}

.uploader img{
  max-width: 464px;
  max-height: 100px;
  z-index:1;
  border:none;
}



.greyLogoBox {
  width: 100%;
  background: #EBEBEB;
  border: 1px solid #D7D7D7;
  text-align: center;
  height: 100px;
  padding-top: 22px;
  box-sizing: border-box;
}


#filePhoto{
  position:absolute;
  width:464px;
  height:100px;
  left:0;
  top:0;
  z-index:2;
  opacity:0;
  cursor:pointer;
}

avant correction mon code était:

function handleImage(e) {
              var reader = new FileReader();
              reader.onload = function (event) {
                  onclick="$('#filePhoto').click()"
                  $('.uploader img').attr('src',event.target.result);
              }
              reader.readAsDataURL(e.target.files[0]);
          }

L'erreur dans la console: 

 enter image description here

Je l'ai résolu en supprimant onclick="$('#filePhoto').click()" de la balise div.

0
spacedev

Les deux invocations du code identique ci-dessous, si diminuées de 1, fonctionnent dans Chrome 32 sur mon ordinateur, par exemple. 17905 vs 17904. S'ils sont exécutés tels quels, ils généreront l'erreur "RangeError: taille maximale de la pile d'appels dépassée". Il semble que cette limite ne soit pas codée en dur mais dépend du matériel de votre machine. Il semble en effet que si elle est invoquée en tant que fonction, cette limite auto-imposée est plus élevée que si elle était invoquée en tant que méthode, c'est-à-dire que ce code utilise moins de mémoire lorsqu'il est invoqué en tant que fonction.

Invoqué comme méthode:

var ninja = {
    chirp: function(n) {
        return n > 1 ? ninja.chirp(n-1) + "-chirp" : "chirp";
    }
};

ninja.chirp(17905);

Invoqué en tant que fonction:

function chirp(n) {
    return n > 1 ? chirp( n - 1 ) + "-chirp" : "chirp";
}

chirp(20889);
0
Elijah Lynn

La question dans mon cas est parce que j'ai des enfants route avec le même chemin avec le parent:

const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    children: [
      { path: '', redirectTo: 'home', pathMatch: 'prefix' },
      { path: 'home', loadChildren: './home.module#HomeModule' },
    ]
  }
];

J'ai donc dû supprimer la ligne de la route des enfants

const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    children: [
      { path: 'home', loadChildren: './home.module#HomeModule' },
    ]
  }
];
0
Amine Harbaoui

Nous avons récemment ajouté un champ à un site d'administration sur lequel nous travaillons - contact_type ... easy right? Eh bien, si vous appelez le type "select" et essayez de l'envoyer via un appel jquery ajax, il échoue avec cette erreur enfouie au fond de jquery.js

$.ajax({
    dataType: "json",
    type: "POST",
    url: "/some_function.php",
    data: { contact_uid:contact_uid, type:type }
});

Le problème est que type: type - je crois que c’est nous nommer l’argument "type" - avoir une variable de valeur nommée type n’est pas le problème. Nous avons changé cela en:

$.ajax({
    dataType: "json",
    type: "POST",
    url: "/some_function.php",
    data: { contact_uid:contact_uid, contact_type:type }
});

Et réécrivez some_function.php en conséquence - problème résolu.

0
Scott

dans mon cas, je reçois cette erreur lors de l’appel ajax et les données que j’ai essayé de transmettre à cette variable n’ont pas été définies, c’est-à-dire qu’elles me montrent cette erreur mais ne décrivent pas cette variable non définie. J'ai ajouté défini que la variable n avait une valeur.

0
asifaftab87

Je sais que ce fil est ancien, mais je pense qu'il vaut la peine de mentionner le scénario dans lequel j'ai trouvé ce problème pour pouvoir aider les autres.

Supposons que vous ayez des éléments imbriqués comme ceci:

<a href="#" id="profile-avatar-picker">
    <span class="fa fa-camera fa-2x"></span>
    <input id="avatar-file" name="avatar-file" type="file" style="display: none;" />
</a>

Vous ne pouvez pas manipuler les événements d'élément enfant à l'intérieur de l'événement de son parent car il se propage à lui-même et effectue des appels récursifs jusqu'à ce que l'exception soit levée.

Donc, ce code va échouer:

$('#profile-avatar-picker').on('click', (e) => {
    e.preventDefault();

    $('#profilePictureFile').trigger("click");
});

Vous avez deux options pour éviter ceci:

  • Déplacez l'enfant à l'extérieur du parent.
  • Appliquez la fonction stopPropagation à l'élément enfant.
0
Weslley Ramos

Je faisais face au même problème Je l'ai résolu en supprimant un nom de champ qui a été utilisé deux fois sur ajax E.g

    jQuery.ajax({
    url : '/search-result',
    data : {
      searchField : searchField,
      searchFieldValue : searchField,
      nid    :  nid,
      indexName : indexName,
      indexType : indexType
    },
.....
0