2012-03-22 21 views
9

Tengo un evento, que puede dispararse solo. Intento que el código sea lo más eficiente posible, pero puede llegar a la cantidad máxima de llamadas en algunas circunstancias, que están fuera de mi control. No es una pila infinita y terminará en algún momento, pero a veces puede colapsar antes de que termine debido al límite.¿Cómo aumentar la cantidad máxima de llamadas en Javascript?

¿Aumentaré la cantidad de llamadas si configuro 2 detectores de eventos similares y divido el código? ¿O qué puedo hacer?

ACTUALIZACIÓN: Se trata de un evento de cambio de DOM (solo funciona con Webkit, por lo que no se preocupan por otros navegadores), que también puede modificar el DOM según algunas condiciones. Todavía no llegué a ese límite, pero teóricamente, potencialmente puede hacerlo. Todavía estoy optimizando el código para hacer menos manipulaciones de DOM como sea posible.

ACTUALIZACIÓN 2: Estoy incluyendo la muestra (no real) ejemplo:

document.addEventListener('DOMSubtreeModified', function(event){ 

    this.applyPolicy(event); 

}, true); 

function applyPolicy(event){ 
    if(typeof event != "undefined"){ 
     event.stopPropagation(); 
     event.stopImmediatePropagation(); 
    } 

    if(!isButtonAllowed){ 
     $('button:not(:disabled)').each(function(){ 

      $(this).attr('disabled', true); 

     }); 
    } 
} 

Esto es sólo un ejemplo de código, pero incluso en este caso, si usted tiene decir 100s de botones, la llamada la pila también estará en 100s. Tenga en cuenta que si usa $('button').attr('disabled', true);, esto causará problemas en la pila de llamadas, porque jQuery intentará modificar el DOM infinitamente.

+1

¿Quizás debería convertir su función recursiva en un bucle '' while''? No puedo imaginar que necesites el efecto secundario de centenares de miles de desencadenantes de eventos para disparar también alguna otra función ... –

+1

Nunca llegó a ese límite, si no al codificar erróneamente un bucle infinito. Muestra el código. – gpasci

+2

Respuesta corta: no hay un mecanismo (estándar) para hacer esto. La única opción entonces es alterar el código. –

Respuesta

6

Si bien es posible que tenga que volver a pensar un poco de código, una posibilidad sería poner una llamada recursiva en un setTimeout en un intervalo determinado. Esto le permite comenzar una nueva pila de llamadas.

Tome este ejemplo ...

var i = 0; 

function start() { 
    ++i; 
    var is_thousand = !(i % 1000); 

    if (is_thousand) 
     console.log(i); 

    if (i >= 100000) 
     return; // safety halt at 100,000 
    else 
     start() 
} 

Sólo registros a la consola en cada intervalo de 1,000. En Chrome excede la pila en algún lugar en el rango 30,000.

DEMO:http://jsfiddle.net/X44rk/


Pero si retrabajo así ...

var i = 0; 

function start() { 
    ++i; 
    var is_thousand = !(i % 1000); 

    if (is_thousand) 
     console.log(i); 

    if (i >= 100000) // safety halt at 100,000 
     return; 
    else if (is_thousand) 
     setTimeout(start, 0); 
    else 
     start(); 
} 

Ahora en cada 1,000, se permitirá que la función devuelva y el siguiente la llamada se realizará de forma asíncrona, iniciando una nueva pila de llamadas.

Tenga en cuenta que esto supone que la función finaliza efectivamente cuando se realiza la llamada recursiva.

También tenga en cuenta que tengo una condición para detenerme en 100,000 por lo que no somos infinitos.

DEMO:http://jsfiddle.net/X44rk/1/

+0

Esto parece interesante. Le daré una oportunidad. ¡Gracias! – Sherzod

+0

@shershams: De nada. Déjeme saber si usted tiene preguntas. –

+1

Probé tu código con millones de recurrencias, todavía funcionaba bien. Estoy implementando mi código usando esta técnica ahora mismo. ¡Gracias! – Sherzod

6

Para cualquier navegador, la cantidad máxima de llamadas funciona bien por miles. Deberías tratar de optimizar el código, tener una gran cantidad de llamadas no es bueno para la velocidad y la memoria.

Si se está ejecutando en esto, que es un indicador de su código está en extrema necesidad de reorganización

+0

la cosa es que el evento está escuchando el cambio de DOM, y después de verificar algunas condiciones, puede modificar el DOM, lo que disparará ese evento nuevamente. Debido a eso, la pila de llamadas puede aumentar bastante rápido. Todavía estoy trabajando en la optimización del código para hacer menos manipulaciones de DOM como sea posible. – Sherzod

+0

Bueno, este es un comentario muy general que conozco ... pero necesita una separación más clara de las preocupaciones. Si escucha eventos de intercambio, significa que confía en su DOM como un 'modelo' o 'modelo de vista'. Hay un montón de cosas mal con eso. Intenta implementar backbone.js, incluso si no te gusta específicamente ... puedes aprender mucho de los buenos patrones de diseño de la interfaz de usuario. – Evert

+0

Estoy usando JavascriptMVC y jQuery. La única forma de reducir la recursión en este caso es reducir el número de manipulaciones DOM, para que no se active tan a menudo ... ¿hay una mejor manera? – Sherzod

0

El tamaño de los pila de llamadas y detalles de aplicación dependerá del entorno de JavaScript su código se ejecuta en. Incluso si puede manipular el uso de la pila para que se ejecute en los entornos que le interesan ahora, existe una gran posibilidad de que el código de pila se bloquee cuando se ejecuta en un entorno que proporciona un tamaño de pila diferente.

Cualquier programa recursivo puede reescribirse como iterativo. Considere si puede hacer eso en su caso. Ver:

Way to go from recursion to iteration

0

Usted puede no, que son dependientes del navegador y, francamente, tienen una gama bastante amplia, por lo que no hay necesidad de preocuparse de que la OMI.

0

Si está llegando al límite de la pila de llamadas, es casi seguro que tenga una serie recursiva de eventos. Los eventos dependen de una pila, por lo que realmente no son la mejor forma de implementar un bucle. En un lenguaje sin eliminación de llamadas de cola, su única opción real es usar las construcciones de bucle estándar como for/in.

0

Después de descubrir que estás censurar código de terceros que puedan estar prestando elementos que no desea prestados, entiendo el verdadero problema de raíz: listas negras nunca se funciona en el código no fiable, eventualmente algún código pasará su lista negra y listo.

Fuera de rediseñar el código tal que ningún código de terceros espera (o se da) el acceso al DOM, mi solución sería la siguiente:

  1. duplicar su DOM en un iframe oculto.
  2. Sandbox el código de terceros en dicho iframe.
  3. En cualquier cambio DOM en el iframe, inspeccione el iframe para ver si hay diferencias entre los dos árboles DOM. Si el cambio pasa de a la lista blanca, acceda a su DOM real (vuelva a conectar las devoluciones de eventos de evento, etc.).
  4. Copie la estructura del DOM "real" después de las actualizaciones en el iframe DOM, eliminando cualquier dato confidencial del mismo en el proceso.

Todavía verificaría un evento DOM en el iframe, pero no lo haría en su página "actual", por lo que no puede ingresar un bucle infinito.

Esto supone que realmente no puede confiar en el código de su tercero para hacer lo que debería hacer. Si solo es incompetencia del proveedor, olvídese de la parte de depuración, pero sígalo con la lista blanca en lugar de la lista negra, de todos modos.

+0

El código en sí es analizado por una secuencia de comandos diferente antes de la publicación, pero el desarrollador de terceros podría haber olvidado desactivar ciertas cosas en algún evento, por lo tanto, debo verificarlo y aplicar esa política. Definitivamente intentaré crear algo realmente simple usando el método que mencionaste. La idea de iframes suena interesante, aunque los odio. ¡Gracias! – Sherzod

Cuestiones relacionadas