2

所以我在javascript中实现了这个功能:当用户打开文档时,它的数据每10秒保存一次,当用户关闭时,它会再保存一次。它似乎运作良好。这是实现:

var data = "blabla";
var saveagain = false;
var t1;

function onDocumentOpen() {
    saveagain = true;
    savedata();
}

function onDocumentClose() {
    saveagain = false;
    savedata();
}

function savedata() {
    if (!saveagain) clearTimeout(t1);
    SaveDataAjaxCall(data, function() {
        //data was saved
        if (saveagain) t1 = setTimeout("savedata()", 10000);
    });
}

我想知道我的方法是否正确,以及它是否会在极端情况下导致一些可能的竞争条件,例如:

当从 onDocumentClose() 调用的 savedata() 实例在 if(!saveagain) 步骤之后,从 setTimeout() 的前一个计时器调用的 savedata() 实例在该步骤之前,因此它会被再次调用。这或者更奇怪的事情会发生吗?

提前致谢

编辑:

在考虑了 TJ Crowder 和 Bengi 的评论后,我最终确定了代码:

var data = "";
var saveagain = false;
var t1;
var beingsaved = false;

function onDocumentOpen() {
    saveagain = true;
    savedata();
}

function onDocumentClose() {
    saveagain = false;
    savedata();
}

function saveData() {
    if (beingsaved) {
        if (!saveagain) setTimeout(saveData, 100);
        return false;
    }
    beingsaved=true;

    if (!saveagain) clearTimeout(t1);

    data=getData();

    SaveDataAjaxCall(data, function() {
        //data was saved
        beingsaved=false;
        if (saveagain) t1 = setTimeout(saveData, 10000);
    });

}

我想我现在已经处理了每一个场合。我认为被保存的解决方案等于 TJ Crowder 建议的原子计数。

EDIT2:嗯,我不确定我是否解决了它,因为可能存在这样一种情况,即 if(beingsaved) 在 onDocumentClose 调用设置为 true 之前被 setTimeout 调用评估。这会发生吗?

4

2 回答 2

2

我假设你的保存操作是异步的,所有好的 ajax 操作都应该是异步的。如果是这样,您将需要在其周围设置某种保护条件,以便两个保存触发器不会重叠。或者,当然,允许它们重叠,但在服务器端处理它(可能使用序列号或时间戳),如果后面的保存已经提交,它会忽略早期的保存。

于 2012-05-21T17:30:43.937 回答
1

不,Javascript 是单线程的(除了 WebWorkers 和 Co 等创新,它们需要在基于事件的接口上进行通信)。

因此,一旦您的同步执行开始(全局脚本、超时、ajax 事件处理程序),它就会运行并且无法停止。其他一切(新事件、0ms 超时等)将在之后安排。

您的脚本包含 2 个异步场景:超时和 ajax 回调。在你开始循环 onDocumentOpen 之后,它就像这样:

  1. 执行saveData:启动ajax请求
  2. 等待(直到 ajax 事件发生)
  3. 执行成功回调:为 saveData 设置新的超时
  4. 等待(直到发生超时事件)
  5. 执行saveData:启动ajax请求
  6. 等待...

...等等。

您的 onDocumentClose 只能在等待期间执行,此时没有其他执行运行。你会期待以下内容:

  1. ...执行 saveData:启动 ajax 请求
  2. 什么都没发生
  3. ajax 事件:执行成功回调:为 saveData 设置新的超时
  4. 什么都没发生
  5. documentClose 事件:清除超时,启动 ajax 请求
  6. 什么都没发生
  7. ajax 事件:执行成功回调:不再设置新的超时。结尾。

但是当在 ajax 请求期间发生 documentClose 时,您并没有保护这种情况:

  1. ...执行 saveData:启动 ajax 请求
  2. 什么都没发生
  3. ajax 事件:执行成功回调:为 saveData 设置新的超时
  4. 什么都没发生
  5. 超时事件:执行saveData,启动ajax请求
  6. 什么都没发生
  7. documentClose 事件:清除(不存在的)超时,启动 ajax 请求(第二次)
  8. 什么都没发生
  9. ajax 事件之一:执行成功回调:不再设置新的超时。
  10. 什么都没发生
  11. 其他 ajax 事件:执行成功回调:不再设置新的超时。结尾。

所以总会走到尽头。如果其中一个事件在某事执行期间触发,则两者之间不会发生“什么都没有发生” - 但它会一个接一个地执行。即使超时应该在 ajax 回调执行期间结束并且在它被清除之前结束,它也会在它结束后被清除时被取消调度:

var id = setTimeout(function(){
    alert("still waiting for execution"); // never alerts
}, 500);
setTimeout(function(){
    alert("still waiting for execution"); // this alerts
}, 500);
for(var d = Date.now(); Date.now()-d < 1000; ) {
    ; // wait - the timeouts end during this heavy processing
}
clearTimeout(id);
于 2012-05-21T17:30:46.493 回答