Javascript中的线程安全性?

Jos*_*rke 34 javascript concurrency asp.net-ajax

我有一个名为save()的函数,该函数收集页面上的所有输入,并对服务器执行AJAX调用以保存用户工作的状态.

当用户单击保存按钮时,当前调用save(),或执行一些需要我们在服务器上具有最新状态的其他操作(例如,从页面生成文档).

我正在增加每隔一段时间自动保存用户工作的能力.首先,我想阻止AutoSave和用户生成的保存同时运行.所以我们有以下代码(我正在削减大部分代码,这不是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's 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);
}
Run Code Online (Sandbox Code Playgroud)

我的问题是这段代码是否安全?主流浏览器是否一次只允许一个线程执行?

我曾经想过,如果用户点击保存并且没有响应会更糟糕,因为我们正在自动保存(而且我知道如何修改代码来处理这个问题).有人在这看到任何其他问题吗?

Jon*_*ust 44

浏览器中的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();
}
Run Code Online (Sandbox Code Playgroud)


mik*_*rey 7

所有主流浏览器仅在页面上支持一个javascript线程(除非您使用Web worker).

但是,XHR请求可以是异步的.但只要您在当前保存返回请求之前禁用保存功能,一切都应该正常.

我唯一的建议是确保以某种方式向用户指示自动保存发生时(禁用保存按钮等).