Мне было интересно, когда существует решение для выполнения синхронизации в коде JavaScript. Например, у меня есть следующий случай: я пытаюсь кэшировать некоторые значения ответа от вызова AJAX, проблема в том, что можно выполнять одновременно несколько вызовов, поэтому это приводит к состоянию гонки в коде. Так что мне очень любопытно найти решение для этого? У кого-нибудь есть идеи, что делать?
Параметры синхронизации JavaScript
Ответы (6)
Я могу предложить возможное решение, но не видя кода... не совсем уверен, что вы делаете, но нет причин, по которым вы не могли бы это сделать.
Базовый код в 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 );
};
});
Javascript по своей сути является однопоточным, по крайней мере, для обычной среды браузера. Никогда не будет двух одновременных запусков скриптов, обращающихся к одному и тому же документу. (новые рабочие потоки Javascript могут быть здесь исключением, но они вообще не предназначены для доступа к документам, а только для обмена сообщениями).
Я нашел решение для моей проблемы. Я должен сказать, что это не так идеально, как я искал, но пока это работает, и я думаю об этом больше как о временной работе.
$.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
}
}
})();
Да, вы можете сделать ваши xmlHttpRequests синхронными, в не-IE установите для параметра asynch значение false при открытом методе в браузерах IE сделайте то же самое с параметром bAsync.
Возможно, вы захотите как-то связать свои запросы. Создайте стек очереди и отправляйте запросы по мере продвижения вниз по очереди.
Во-первых, важно знать, что все текущие реализации JS являются однопоточными, поэтому мы не обсуждаем условия гонки и синхронизацию в том контексте, в котором она обычно используется.
В качестве примечания, браузеры теперь вводят рабочие потоки, которые позволяют параллелизм в JS, но на данный момент это не так.
В любом случае, вы по-прежнему сталкиваетесь с проблемами, связанные с тем, какие данные вы ожидаете получить обратно от асинхронных вызовов, и у вас нет никаких гарантий относительно порядка их получения.
JS дает вам очень хорошее решение с обратными вызовами. Для каждого асинхронного события, которое вы будете отправлять, прикрепите к нему соответствующую функцию обратного вызова, которая будет правильно обрабатывать событие. Синхронизация, в том смысле, в каком вы это имеете в виду, должна происходить там.
Я знаю, что это далеко после, но думал, что просто дам улучшение. Артем Баргер разработал собственное решение, которое использует setTimeout, если кешированное значение «обновляется»… Вместо этого просто пометьте функцию в связанной очереди против кешированного значения, чтобы у вас был объект, который содержит фактические кешированные данные и очередь функций. для вызова с кэшированными данными после возврата данных.
Итак, если он «обновляется», просто добавьте свою функцию в очередь, которая связана с данными элемента, и когда данные возвращаются... установите данные, а затем выполните итерацию по очереди функций (обратных вызовов) и вызовите их с возвращенным данные.
если вы хотите получить техническую информацию, вы можете установить определенный тайм-аут QOS при прохождении очереди, установить секундомер в начале итерации, и если вы достигнете определенного времени, затем вызовите setTimeout, чтобы вернуться в очередь, чтобы продолжить итерация ... Надеюсь, вы это поняли :) - В основном это экономит X количество вызовов setTimout, нужен только один.
Просмотрите код Artem Bargers выше, и вы должны понять суть того, что я предлагаю.