Error de tamaño de pila de llamadas máximo excedido

533

Estoy usando un archivo de biblioteca JavaScript de Direct Web Remoting (DWR) y obtengo un error solo en Safari (escritorio y iPad)

Dice

Se excedió el número máximo de llamadas a la pila.

¿Qué significa exactamente este error y deja de procesarse por completo?

También cualquier solución para el Safarinavegador (en realidad en el iPad Safari, dice

JS: la ejecución excedió el tiempo de espera

que supongo que es el mismo problema de pila de llamadas)

testndtv
fuente
2
Recibí este error al intentar enviar variables (sin declararlas), a través datade ajax. Se corrigió el error declarando las variables.
phpfresher

Respuestas:

621

Significa que en algún lugar de su código, está llamando a una función que a su vez llama a otra función y así sucesivamente, hasta que alcanza el límite de la pila de llamadas.

Esto casi siempre se debe a una función recursiva con un caso base que no se cumple.

Viendo la pila

Considera este código ...

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

Aquí está la pila después de un puñado de llamadas ...

Inspector web

Como puede ver, la pila de llamadas crece hasta alcanzar un límite: el tamaño de la pila codificada por el navegador o el agotamiento de la memoria.

Para solucionarlo, asegúrese de que su función recursiva tenga un caso base que se pueda cumplir ...

(function a(x) {
    // The following condition 
    // is the base case.
    if ( ! x) {
        return;
    }
    a(--x);
})(10);
alex
fuente
66
Muchas gracias por eso ... Entonces, ¿hay alguna manera / herramienta por la cual pueda que el límite de la pila se esté agotando ... De nuevo, como este es un gran archivo de biblioteca y no fue creado por mí, no estoy completamente consciente de dónde las cosas podrían ir mal ..
testndtv
52
@Oliver Si tiene que ejecutar una función casi 300 billones de veces, probablemente esté haciendo algo mal.
ceejayoz
3
@Oliver: es posible que desee analizar la programación dinámica; supongo que no tiene tantas soluciones únicas, está repitiendo los pasos, por lo que es posible que deba programarlo para que sea un tiempo polinumial en lugar de cuadrático. en.wikipedia.org/wiki/Dynamic_programming
newshorts
44
@ Akhoy En una función regular sí, pero piense en una función recursiva. Llama a otro (a sí mismo) y deja la dirección de retorno del primero en la pila (de lo contrario, ¿dónde sabría la PC a dónde ir?) Esto, por supuesto, se llama a sí mismo nuevamente, cada vez que empuja una dirección de retorno a la pila. Cuando esto se escapa debido a un caso base que no es probable que se cumpla en el próximo siglo, se obtiene un desbordamiento de pila.
alex
55
Su código ejecuta ese mismo segmento ineficiente 134217728 veces. No es broma es lento. Debe usar operadores bit a bit para poder desenrollar los 9 niveles de bucles en un nivel de bucles.
Jack Giffin
82

A veces puede obtener esto si accidentalmente importa / incrusta el mismo archivo JavaScript dos veces, vale la pena revisarlo en la pestaña de recursos del inspector.

lucygenik
fuente
99
Este problema generalmente ocurre cuando accidentalmente importa / incrusta dos veces el mismo archivo JS. El proceso exacto que causa el bucle recursivo no es algo en lo que quiera especular, sin embargo, supongo que es algo así como conducir dos autos idénticos a 100 mph a través de la misma pasarela de peaje.
lucygenik
3
No creo que este sea el caso. Si se incorporan dos tipos de funciones o variables, esta última anulará las definiciones anteriores.
ssudaraka
Sí ... Realmente no sé por qué sucede o cuál es el proceso, aunque habría anulado también.
lucygenik
Un poco tarde para la fiesta, pero imagino que es cuando el código está fuera de cualquier función, ambos se ejecutarán dentro de los dos archivos JS, y uno probablemente no se sobrescribirá entre sí, ya que están fuera de cualquier función.
Cillian Collins
1
@lucygenik la próxima vez que quieras ser más cuidadoso al aprobar ediciones troll en tus publicaciones. Esta publicación casi se eliminó como spam (consulte el historial)
Jean-François Fabre
57

En mi caso, estaba enviando elementos de entrada en lugar de sus valores:

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

En vez de:

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

Esto congeló mi pestaña de Chrome hasta un punto que ni siquiera me mostró el cuadro de diálogo 'Esperar / matar' cuando la página dejó de responder ...

FKasa
fuente
3
Me pregunto por qué no hay una excepción para tal error ... ¡Gracias!
Džuris
Muchas gracias, esto me salvó
Eme Hado
Estaba a punto de agregar esto como una posible solución. Acabo de hacer esto exactamente jajaja
Michael Buchok
31

Hay un bucle recursivo en algún lugar de su código (es decir, una función que eventualmente se llama una y otra vez hasta que la pila esté llena).

Otros navegadores tienen pilas más grandes (por lo que obtienes un tiempo de espera en su lugar) o se tragan el error por alguna razón (tal vez un try-catch mal colocado).

Use el depurador para verificar la pila de llamadas cuando ocurre el error.

Aaron Digulla
fuente
Muchas gracias por su respuesta. En IE / FF, el código parece funcionar bien ... Solo en el escritorio Safari y iPad Safari, recibo el error. En realidad, el archivo JS no es mi propia creación, sino que es un archivo de biblioteca (de DWR engine.js). Directwebremoting.org También cuando dices "depurador para verificar la pila de llamadas", ¿cómo hago eso usando Safari Inspector?
testndtv
No tengo experiencia con Safari Inspector. Intenta abrir el depurador de JavaScript y carga tu página. El depurador debe detenerse cuando se produce un error no detectado. Si eso no funciona, pregunte por el superusuario o los webmasters (vea la parte inferior de la página)
Aaron Digulla
¡Tenía 2 funciones llamadas lo mismo! DOH!
jharris8567
16

El problema con la detección de flujos de stackover es que a veces el seguimiento de la pila se desenrollará y no podrá ver lo que realmente está sucediendo.

He encontrado algunas de las nuevas herramientas de depuración de Chrome útiles para esto.

Presiona Performance tab, asegúrate de que Javascript samplesestén habilitados y obtendrás algo como esto.

¡Es bastante obvio dónde está el desbordamiento aquí! Si hace clic en extendObjectpodrá ver el número de línea exacto en el código.

ingrese la descripción de la imagen aquí

También puede ver los tiempos que pueden o no ser útiles o un arenque rojo.

ingrese la descripción de la imagen aquí


Otro truco útil si realmente no puede encontrar el problema es poner muchas console.logdeclaraciones donde cree que está el problema. El paso anterior anterior puede ayudarlo con esto.

En Chrome, si genera datos idénticos repetidamente, los mostrará de esta manera, mostrando dónde está el problema más claramente. En este caso, la pila alcanzó 7152 fotogramas antes de que finalmente se bloqueara:

ingrese la descripción de la imagen aquí

Simon_Weaver
fuente
13

En mi caso, estaba convirtiendo una gran matriz de bytes en una cadena usando lo siguiente:

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

bytes contenía varios millones de entradas, que es demasiado grande para caber en la pila.

Nate Glenn
fuente
¡Yo también tuve el mismo problema con la misma línea! gracias
ksh
Entonces, ¿cuál es la mejor solución para convertir una gran matriz de bytes?
ksh
66
@KarthikHande Tienes que hacerlo en un bucle for en lugar de en una sola llamada. var uintArray = new Uint16Array(bytes); var converted = []; uintArray.forEach(function(byte) {converted.push(String.fromCharCode(byte))});
Nate Glenn
¿Cómo convierto eso a JSON? Intenté JSON.parse pero no funcionó ... Estoy usando Uintl8Array
ksh
@KarthikHande No puedo decirlo sin ver todo el problema. Abre otra pregunta con todos los detalles.
Nate Glenn
6

En mi caso, el evento click se propagaba en el elemento hijo. Entonces, tuve que poner lo siguiente:

e.stopPropagation ()

evento 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");
 });

Aquí está el código html:

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

Verifique los detalles del error en la consola de la barra de herramientas de desarrollo de Chrome, esto le dará las funciones en la pila de llamadas y lo guiará hacia la recurrencia que está causando el error.

chim
fuente
3

Casi todas las respuestas aquí indican que esto solo puede ser causado por un bucle infinito. Eso no es cierto, de lo contrario, podría sobrepasar la pila a través de llamadas profundamente anidadas (por no decir que es eficiente, pero ciertamente es posible). Si tiene control de su máquina virtual JavaScript, puede ajustar el tamaño de la pila. Por ejemplo:

node --stack-size=2000

Consulte también: ¿Cómo puedo aumentar el tamaño máximo de la pila de llamadas en Node.js?

ghayes
fuente
2

En mi caso, dos modales jQuery se mostraban apilados uno encima del otro. Prevenir eso resolvió mi problema.

Barry Guvenkaya
fuente
2

Recientemente agregamos un campo a un sitio de administración en el que estamos trabajando - contact_type ... fácil ¿verdad? Bueno, si llama al select "type" e intenta enviarlo a través de una llamada jquery ajax, falla con este error enterrado en jquery.js No haga esto:

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

El problema es ese tipo: tipo: creo que somos nosotros los que nombramos el argumento "tipo"; tener una variable de valor llamada tipo no es el problema. Cambiamos esto a:

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

Y reescribí some_function.php en consecuencia, problema resuelto.

Scott
fuente
1

Comprueba si tienes una función que se llame a sí misma. Por ejemplo

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

Esto también puede causar un Maximum call stack size exceedederror:

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

Igual que aquí:

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

De los documentos de Mozilla :

Pero tenga cuidado: al usar Apply de esta manera, corre el riesgo de exceder el límite de longitud del argumento del motor JavaScript. Las consecuencias de aplicar una función con demasiados argumentos (piense más de decenas de miles de argumentos) varían entre motores (JavaScriptCore tiene un límite de argumento codificado de 65536), porque el límite (incluso la naturaleza de cualquier pila excesivamente grande comportamiento) no está especificado. Algunos motores arrojarán una excepción. Más perniciosamente, otros limitarán arbitrariamente el número de argumentos realmente pasados ​​a la función aplicada. Para ilustrar este último caso: si dicho motor tuviera un límite de cuatro argumentos (los límites reales son, por supuesto, significativamente más altos), sería como si los argumentos 5, 6, 2, 3 se hubieran pasado para aplicar en los ejemplos anteriores, en lugar de la matriz completa.

Entonces intenta:

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

Ambas invocaciones del código idéntico a continuación si disminuyen en 1 funcionan en Chrome 32 en mi computadora, por ejemplo, 17905 frente a 17904. Si se ejecutan tal cual, producirán el error "RangeError: Se excedió el tamaño máximo de la pila de llamadas". Parece que este límite no está codificado sino que depende del hardware de su máquina. Parece que si se invoca como una función, este límite autoimpuesto es mayor que si se invoca como un método, es decir, este código en particular usa menos memoria cuando se invoca como una función.

Se invoca como método:

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

ninja.chirp(17905);

Se invoca como una función:

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

chirp(20889);
Elijah Lynn
fuente
0

puede encontrar su función recursiva en el navegador crome, presione ctrl + shift + j y luego la pestaña fuente, que le brinda el flujo de compilación de código y puede encontrarlo usando el punto de interrupción en el código.

Vishal Patel
fuente
Sin embargo, a veces puede ser difícil averiguar dónde se originó el error. Tenemos MUCHOS JavaScript en nuestro sitio.
Mathias Lykkegaard Lorenzen
0

También me enfrenté a un problema similar aquí: los detalles al cargar el logotipo utilizando el cuadro desplegable de carga del logotipo

<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;
}

antes de la corrección mi código era:

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]);
          }

El error en la consola:

ingrese la descripción de la imagen aquí

Lo resolví eliminando onclick="$('#filePhoto').click()"de la etiqueta div.

spacedev
fuente
¿Dónde
agregaste
0

Estaba enfrentando el mismo problema, lo resolví eliminando un nombre de campo que se usó dos veces en ajax, por ejemplo

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

Sé que este hilo es antiguo, pero creo que vale la pena mencionar el escenario en el que encontré este problema para que pueda ayudar a otros.

Supongamos que tiene elementos anidados como este:

<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>

No puede manipular los eventos del elemento hijo dentro del evento de su padre porque se propaga a sí mismo, haciendo llamadas recursivas hasta que se lanza la excepción.

Entonces este código fallará:

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

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

Tienes dos opciones para evitar esto:

  • Mueva al niño al exterior del padre.
  • Aplique la función stopPropagation al elemento hijo.
Weslley Ramos
fuente
0

Tuve este error porque tenía dos funciones JS con el mismo nombre

dragón de hielo
fuente
0

Si está trabajando con google maps, compruebe si los lat lng que se están pasando new google.maps.LatLngtienen un formato adecuado. En mi caso, se pasaban como indefinidos.

Usuario-8017771
fuente
0

El problema en mi caso es porque tengo rutas de niños con la misma ruta con los padres:

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

Así que tuve que quitar la línea de la ruta de los niños.

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

en mi caso recibo este error en una llamada ajax y los datos que intenté pasar esa variable no se han definido, eso me muestra este error pero no describe esa variable no definida. Agregué definido que la variable n tiene valor.

asifaftab87
fuente
Me quemé de manera similar, en mi caso fue porque escribí un nombre de variable ... efectivamente, lo mismo.
user2366842
0

Me he encontrado con el mismo problema, no podría haber descubierto lo que está mal y comenzó a culpar a Babel;)

Tener código que no devuelve ninguna excepción en los navegadores:

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

problema fue mal creado || (o) parte cuando babel crea su propia verificación de tipo:

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

así que quitando

|| null

hizo que la transpiración de babel funcionara.

Rafael
fuente
0

En mi caso, por error, he asignado el mismo nombre de variable y a la función val "class_routine_id"

var class_routine_id = $("#class_routine_id").val(class_routine_id);

debería ser como:

 var class_routine_id = $("#class_routine_id").val(); 
Alok Jha
fuente
0

Estoy usando React-Native 0.61.5 junto con ( npm 6.9.0 y nodo 10.16.1 )

Mientras instalo cualquier biblioteca nueva en Project, obtuve una de

(por ejemplo, npm install @ react-navigation / native --save)

Error de tamaño de pila de llamadas máximo excedido

por eso lo intento

sudo npm cache clean --force

(Nota: - El siguiente comando generalmente demora de 1 a 2 minutos, dependiendo del tamaño de su caché npm )

DevAelius
fuente
-1

A veces sucedió debido al tipo de datos de conversión, por ejemplo, tiene un objeto que consideró como cadena.

socket.id en nodejs, ya sea en el cliente js como ejemplo, no es una cadena. Para usarlo como cadena, debe agregar la palabra Cadena antes:

String(socket.id);
Hussein mahyoub
fuente
-1

Estaba tratando de asignar una variable, un valor, cuando esa variable no se había declarado.

Declarar la variable corrigió mi error.

Phillip Quinlan
fuente