Параметры синхронизации JavaScript - PullRequest
10 голосов
/ 09 мая 2009

Мне было интересно, когда бы ни существовало решение для выполнения синхронизации в коде JavaScript. Например, у меня есть следующий случай: я пытаюсь кэшировать некоторые значения ответа от вызова AJAX, проблема в том, что возможно выполнить одновременно несколько вызовов, поэтому это приводит к состоянию гонки в коде. Так что мне очень интересно найти решение для этого? У кого-нибудь есть идеи, что делать?

Ответы [ 6 ]

8 голосов
/ 09 мая 2009

Я могу предложить возможное решение, но не видя код ... не совсем уверен, что вы делаете, но нет никаких причин, почему вы не могли этого сделать.

Базовый код в jQuery: (не проверено и не сокращено ... но я делал похожие вещи)

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

РЕДАКТИРОВАТЬ: (re: ваш комментарий)

Вы ищете обратные вызовы, так же, как jQuery сделает это.

   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 );              
        };            
    });
6 голосов
/ 09 мая 2009

Javascript по своей природе является однопоточным, по крайней мере, для нормальной среды браузера. Никогда не будет двух одновременных исполнений скриптов, обращающихся к одному и тому же документу. (новые рабочие потоки Javascript могут быть здесь исключением, но они вовсе не предназначены для доступа к документам, просто для обмена сообщениями).

4 голосов
/ 11 мая 2009

Я нашел решение для моей проблемы. Я должен сказать, что это не так идеально, как я искал, но пока это работает, и я думаю об этом скорее как временное решение.

$.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
        }
    }
})();
3 голосов
/ 09 мая 2009

Во-первых, важно знать, что все текущие реализации JS являются однопоточными, поэтому мы не обсуждаем условия гонки и синхронизируемся в контексте, который обычно используется.

В качестве примечания, браузеры теперь вводят рабочие потоки, которые разрешают параллелизм в JS, но сейчас это не так.

В любом случае, вы все еще сталкиваетесь с проблемами в отношении того, какие данные вы ожидаете получить обратно из асинхронных вызовов, и у вас нет никаких гарантий относительно порядка получения данных.

JS дает вам очень хорошее решение для этого с помощью обратных вызовов. Для каждого асинхронного события, которое вы будете отправлять, прикрепите к нему соответствующую функцию обратного вызова, которая будет правильно обрабатывать событие. Синхронизация , в том смысле, в каком вы это имеете в виду, должна происходить там.

3 голосов
/ 09 мая 2009

Да, вы можете сделать ваши xmlHttpRequests синхронными, в не-IE установите опцию asynch на false в методе open, в браузерах IE выполните то же самое с параметром bAsync.

Может быть, вы захотите как-нибудь связать свои запросы. Создайте стек очереди и отправляйте запросы по мере продвижения по очереди.

1 голос
/ 19 сентября 2017

Я знаю, что это намного позже, но подумал, что просто улучшу. Артем Баргер разработал свое собственное решение, которое использует setTimeout, если кэшированное значение «обновляется» ... Вместо этого просто пометьте функцию в связанной очереди с кэшированным значением, чтобы у вас был объект, который содержит фактические кэшированные данные и очередь функций вызывать с кэшированными данными после того, как данные возвращены.

Итак, если это «обновление», просто добавьте свою функцию в очередь, которая связана с данными элемента, а когда данные вернутся ... установите данные, а затем выполните итерацию по очереди функций (обратных вызовов) и вызовите их с возвращенными данными.

если вы хотите получить техническую информацию, вы можете установить определенный тайм-аут QOS при прохождении очереди, установить секундомер в начале итерации, а если вы достигнете определенного времени, тогда вызовите setTimeout, чтобы вернуться в очередь. продолжить итерацию ... Я надеюсь, что вы получили это :) - Это в основном экономит X количество вызовов setTimout, необходим только один.

Посмотрите код Артема Баргерса выше, и вы должны понять суть того, что я предлагаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...