2009-05-09 19 views
10

Me preguntaba si existe una solución para realizar la sincronización en código JavaScript. Por ejemplo, tengo el siguiente caso: estoy tratando de almacenar en caché algunos valores de respuesta de la llamada AJAX, el problema es que es posible realizar simultáneamente varias llamadas, por lo tanto, conduce a una condición de carrera en el código. Entonces, ¿tengo mucha curiosidad por encontrar una solución para eso? ¿Alguien tiene idea de eso?Opciones de sincronización de JavaScript

Respuesta

4

He encontrado la solución a mi problema. Tengo que decir que no es tan perfecto como estaba buscando, pero hasta ahora funciona y pienso en eso más temporalmente.

$.post("url1", function(data) 
{ 
    // do some computation on data and then 
    setSomeValue(data); 
}); 

var setSomeValue = (function() 
{ 
    var cache = {}; 
    return function(data) 
    { 
     if (cache[data] == "updating") 
     { 
      setTimeout(function(){ setSomeValue(data);}, 100); 
      return; 
     } 
     if (!cache[date]) 
     { 
      cache[date] = updating; 
      $.post("url2", function(another_data) 
      { 
        //make heavy computation on another_data 
        cache[data] = value; 
        // update the UI with value 
      }); 
     } 
     else 
     { 
      //update the UI using cached value 
     } 
    } 
})(); 
+0

Gracias por esto. Me sorprende cómo muchos dijeron "es de un solo hilo así que no es un problema", lo cual es totalmente incorrecto en un mundo con devoluciones de llamada asincrónicas. Usted describió el problema muy bien y este es un enfoque perfectamente efectivo para mí. –

6

Javascript es intrínsecamente de subproceso único, al menos para el entorno de navegador normal. Nunca habrá dos ejecuciones simultáneas de scripts accediendo al mismo documento. (Los nuevos subprocesos de trabajo de Javascript pueden ser una excepción aquí, pero no están destinados a acceder a documentos en absoluto, solo para comunicarse mediante el envío de mensajes).

+1

El Javascript puede ser de una sola hebra pero puede tener condiciones de carrera, no hay garantía del orden en que se realizan las solicitudes asíncronas, cuando se completan, etc. Esto es especialmente cierto con los complementos de Firefox y múltiples ventanas. –

+1

obviamente necesita escribir código que pueda manejar los problemas que describe. Este no es el mismo tipo de sincronización que necesita en otros idiomas para evitar que los hilos interfieran entre sí leyendo resultados incompletos de la memoria o sobrescribiendo los cambios de los demás entre operaciones más grandes. Solo hay una secuencia activa de ejecución de JavaScript en el entorno del navegador. todos los manejadores de eventos son llamados en forma serializada, uno tras otro. – fforw

+1

Simplemente intente escribir, por ejemplo, una llamada AJAX, luego en el controlador llamar a otra solicitud AJAX, y en el segundo controlador acceder a una variable global. Y ahora haga varias iteraciones de la primera llamada. ¿Todavía estás seguro de que hay un acceso serializado a esa variable? ¿Podrías predecir el orden? Y una cosa más si pudiera escribir código de trabajo para el problema que he descrito, nunca solicitaría ayuda aquí. –

3

Sí, puede hacer que sus xmlHttpRequests sean síncronas, en no-IE configure asynch option como falso en el método abierto, en los navegadores IE do the same con el parámetro bAsync.

Quizás desee encadenar sus solicitudes de alguna manera. Cree una pila de que y envíe las solicitudes a medida que avanza por la que.

+1

las solicitudes síncronas son malas porque impiden que se ejecuten todos los demás controladores de eventos de JavaScript. – fforw

+0

Acabo de responder su pregunta, no intenté juzgar su necesidad. ¿Vota abajo eso? heh. –

+0

Es posible que las personas deseen la sincronización por muchas razones diferentes, por ejemplo, si desea que se procese una solicitud antes de manipular más entradas del usuario. Hay otras razones Etc. –

3

En primer lugar, es importante saber que todas las implementaciones actuales de JS son de subproceso único, por lo tanto, no estamos discutiendo las condiciones de carrera y la sincronización en el contexto en el que generalmente se usa.

Como nota al margen, los navegadores ahora están introduciendo subprocesos de trabajo que permitirán la concurrencia en JS, pero por ahora este no es el caso.

De todos modos, todavía tiene problemas con los datos que espera recibir de las llamadas asincrónicas y no tiene garantía en cuanto al orden en que recibirá las cosas.

JS le ofrece una solución muy buena para esto con devoluciones de llamada. Para cada evento asíncrono que va a enviar, adjunte una función de devolución de llamada adecuada, que manejará el evento correctamente. Sincronización, en la forma en que lo dices, debería estar sucediendo allí.

+0

Ok, en mi caso, estoy tratando de construir el caché para algunas respuestas del servidor. Hay una llamada AJAX, que tiene su propio manejador, pero en el manejador hay una llamada a la función, que accediendo a la variable de caché y si la variable está configurada, úselo de manera excesiva y realice otra pesada llamada AJAX. Por lo tanto, si uso una llamada asíncrona, es probable que pierda la actualización de la memoria caché y realice una llamada innecesaria dos veces; este comportamiento no está dispuesto, así que estaba pensando en la forma en que podría sincronizar el acceso para leer/escribir esa variable. –

8

Puedo ofrecer una posible solución, pero sin ver el código ... no estoy completamente seguro de lo que está haciendo, pero no hay ninguna razón por la que no pueda hacer esto.

código básico en jQuery: (no probado y abrevia ... pero he hecho cosas similares)

var needAllThese = {}; 

$(function(){ 

     $.ajax("POST","/somepage.aspx",function(data) { 
      needAllThese.A = "VALUE"; 
     }); 

     $.ajax("POST","/somepage2.aspx",function(data) { 
      needAllThese.B = "VALUE"; 
     }); 

     $.ajax("POST","/somepage3.aspx",function(data) { 
      needAllThese.C = "VALUE"; 
     }); 

     startWatching(); 
}); 

function startWatching() { 
    if (!haveEverythingNeeded()) { 
     setTimeout(startWatching,100); 
     return; 
    } 
    everythingIsLoaded(); 
} 

function haveEverythingNeeded() { 
    return needAllThese.A && needAllThese.B && needAllThese.C; 
} 

function everythingIsLoaded() { 
    alert("Everything is loaded!"); 
} 

EDIT: (re: su comentario)

que estás buscando devoluciones de llamada, de la misma manera que jQuery lo haría.

var cache = {}; 

    function getSomeValue(key, callback) { 
     if (cache[key]) callback(cache[key]); 

     $.post("url", function(data) { 
      setSomeValue(key,data); 
      callback(cache[key]); 
     }); 
    } 

    function setSomeValue(key,val) { 
     cache[key] = val; 
    } 

    $(function(){  
     // not sure you would need this, given the code above 
     for (var i = 0; i < some_length; ++i) { 
      $.post("url", function(data){ 
       setSomeValue("somekey",data); 
      }); 
     } 

     getSomeValue("somekey",function(val){    
      $("#element").txt(val);    
     };    
    }); 
+0

código es el siguiente: $ (function() { for (var i = 0; i

+0

Para ser honesto, no estoy seguro de entender cómo la última solución me ayudará en mi problema. ¿Te importa explicar un poco? –

+0

Hace exactamente lo que pidió. El uso de devoluciones de llamada ... y si escribió el código de ejemplo en su comentario, está utilizando devoluciones de llamada en su llamada. $ Post, es el mismo concepto ... no debería tener problemas para entenderlo a menos que no haya escrito el código tiene problemas con –

1

Sé que es mucho después, pero pensé que solo mejoraría. Artem Barger desarrolló su propia solución que usa setTimeout si el valor almacenado en caché es "actualizando" ... En su lugar, simplemente etiquete la función en una cola vinculada contra el valor en caché para que tenga un objeto que contenga los datos almacenados en caché y la cola de funciones llamar con los datos en caché una vez que se devuelven los datos.

Por lo tanto, si está "actualizando" simplemente agregue su función a la cola que está vinculada a los datos del artículo y cuando los datos vuelven ...establecer los datos y luego iterar sobre la cola de funciones (devoluciones de llamada) y llamarlos con los datos devueltos.

si desea obtener información técnica, puede establecer un tiempo de espera de QOS específico a medida que avanza en la cola, establecer un cronómetro al comienzo de la iteración y si llega a una hora específica, llame a setTimeout para volver al hacer cola para continuar la iteración ... Espero que lo hayas conseguido :) - Básicamente se ahorra una cantidad X de llamadas setTimout, solo se necesita una.

Ver el código de Artem Bargers anterior y usted debe obtener la esencia de lo que propongo.

Cuestiones relacionadas