Подтвердить что ты не робот

Безопасность потоков в Javascript?

У меня есть функция, называемая save(), эта функция собирает все входы на странице и выполняет вызов AJAX на сервер, чтобы сохранить состояние работы пользователя.

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

Я добавляю возможность автоматического сохранения работы пользователя так часто. Сначала я хотел бы предотвратить автоматическое сохранение Автосохранения и сгенерированного пользователем сохранения. Таким образом, у нас есть следующий код (я сокращаю большую часть кода, и это не 1:1, но должно быть достаточно, чтобы передать идею):

var isSaving=false;
var timeoutId;
var timeoutInterval=300000;
function save(showMsg)
{
  //Don't save if we are already saving.
  if (isSaving)
  { 
     return;
  }
  isSaving=true;
  //disables the autoSave timer so if we are saving via some other method
  //we won't kick off the timer.
  disableAutoSave();

  if (showMsg) { //show a saving popup}
  params=CollectParams();
  PerformCallBack(params,endSave,endSaveError);

}
function endSave()
{  
    isSaving=false;
    //hides popup if it visible

    //Turns auto saving back on so we save x milliseconds after the last save.
    enableAutoSave();

} 
function endSaveError()
{
   alert("Ooops");
   endSave();
}
function enableAutoSave()
{
    timeoutId=setTimeOut(function(){save(false);},timeoutInterval);
}
function disableAutoSave()
{
    cancelTimeOut(timeoutId);
}

Мой вопрос в том, безопасен ли этот код? Могут ли основные браузеры одновременно выполнять только один поток?

Одна мысль, что у меня было, было бы хуже, если бы пользователь нажал кнопку "Сохранить" и не получил ответа, потому что мы автосохраняемся (и я знаю, как изменить код, чтобы справиться с этим). Кто-нибудь видит другие проблемы здесь?

4b9b3361

Ответ 1

JavaScript в браузерах однопоточный. Вы всегда будете в одной функции в любой момент времени. Функции будут выполнены до следующего ввода. Вы можете рассчитывать на это поведение, поэтому, если вы находитесь в своей функции save(), вы никогда не введете его снова, пока не закончите текущий.

Если это иногда путается (и все же остается верным), когда у вас есть асинхронные запросы сервера (или setTimeouts или setIntervals), потому что тогда кажется, что ваши функции чередование. Это не так.

В вашем случае, в то время как два вызова save() не будут перекрываться друг с другом, ваше автоматическое сохранение и сохранение пользователя могут происходить обратным образом.

Если вы хотите, чтобы сохранение происходило, по крайней мере, каждые x секунд, вы можете сделать setInterval в своей функции сохранения и забыть об этом. Я не вижу необходимости в флаге isSaving.

Я думаю, что ваш код можно было бы упростить:

var intervalTime = 300000;
var intervalId = setInterval("save('my message')", intervalTime);
function save(showMsg)
{
  if (showMsg) { //show a saving popup}
  params=CollectParams();
  PerformCallBack(params, endSave, endSaveError);

  // You could even reset your interval now that you know we just saved.
  // Of course, you'll need to know it was a successful save.
  // Doing this will prevent the user clicking save only to have another
  // save bump them in the face right away because an interval comes up.
  clearInterval(intervalId);
  intervalId = setInterval("save('my message')", intervalTime);
}

function endSave()
{
    // no need for this method
    alert("I'm done saving!");
}

function endSaveError()
{
   alert("Ooops");
   endSave();
}

Ответ 2

Все основные браузеры поддерживают только один поток javascript (если вы не используете веб-работников) на странице.

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

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

Ответ 3

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

Для получения нескольких ссылок см. Является ли JavaScript многопоточным?

Ответ 4

Мне кажется безопасным. Javascript является однопоточным (если вы не используете веб-мастеров)

Это не совсем по теме, но этот пост Джона Ресига охватывает потоки и таймеры javascript: http://ejohn.org/blog/how-javascript-timers-work/

Ответ 5

Я думаю, что то, как вы справляетесь с этим, лучше всего подходит для вашей ситуации. Используя флаг, вы гарантируете, что асинхронные вызовы не перекрываются. Мне также приходилось иметь дело с асинхронными вызовами на сервере, а также использовать какой-то флаг для предотвращения перекрытия.

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

Одна вещь, однако, заключается в том, что я не думаю, что вам действительно нужно отключить автоматическое сохранение. Если автоматическое сохранение будет происходить при сохранении пользователем, метод сохранения просто вернется и ничего не произойдет. С другой стороны, вы автоматически отключите и повторно активируете автосохранение при каждом включении автосохранения. Я бы рекомендовал изменить на setInterval, а затем забыть об этом.

Кроме того, я сторонник минимизации глобальных переменных. Я бы, вероятно, реорганизовал ваш код следующим образом:

var saveWork = (function() {
  var isSaving=false;
  var timeoutId;
  var timeoutInterval=300000;
  function endSave() {  
      isSaving=false;
      //hides popup if it visible
  }
  function endSaveError() {
     alert("Ooops");
     endSave();
  }
  function _save(showMsg) {
    //Don't save if we are already saving.
    if (isSaving)
    { 
     return;
    }
    isSaving=true;

    if (showMsg) { //show a saving popup}
    params=CollectParams();
    PerformCallBack(params,endSave,endSaveError);
  }
  return {
    save: function(showMsg) { _save(showMsg); },
    enableAutoSave: function() {
      timeoutId=setInterval(function(){_save(false);},timeoutInterval);
    },
    disableAutoSave: function() {
      cancelTimeOut(timeoutId);
    }
  };
})();

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

Изменить: Забытый должен был создать частную функцию сохранения, чтобы иметь возможность ссылаться на enableAutoSave