这是场景:

向我的用户显示了一个网格,基本上是一个电子表格的精简版本。网格中的每一行都有文本框。当他们在文本框中更改值时,我将对其输入执行验证,更新驱动网格的集合,并在页面上重新绘制小计。所有这些都由每个文本框的OnChange事件处理。

当他们单击“保存”按钮时,我正在使用按钮的OnClick事件对金额执行一些最终验证,然后将其全部输入发送到Web服务,进行保存。

至少,如果他们在表单中选择“提交”按钮,就会发生这种情况。

问题是,如果他们输入一个值,然后立即单击保存按钮,则SaveForm()在UserInputChanged()完成之前开始执行-这是一种竞争条件。我的代码没有使用setTimeout,但是我正在使用它来模拟缓慢的UserInputChanged验证代码:

 <!-- snip -->
 <script>
    var amount = null;
    var currentControl = null;

    function UserInputChanged(control) {
        currentControl = control;
        // use setTimeout to simulate slow validation code (production code does not use setTimeout)
        setTimeout("ValidateAmount()", 100);
    }

    function SaveForm() {
        // call web service to save value
        document.getElementById("SavedAmount").innerHTML = amount;
    }

    function ValidateAmount() {
        // various validationey functions here
        amount = currentControl.value; // save value to collection
        document.getElementById("Subtotal").innerHTML = amount; // update subtotals

    }
</script>
<!-- snip -->
Amount: <input type="text" id="UserInputValue" onchange="UserInputChanged(this);" /> <br />
Subtotal: <span id="Subtotal"></span> <br />
<input type="button" onclick="SaveForm();" value="Save" /> <br /><br />
Saved amount: <span id="SavedAmount"></span>
<!-- snip -->

我认为我无法加快验证代码的速度-它相当轻巧,但是显然,它的速度很慢,以至于代码在验证完成之前会尝试调用Web服务。

在我的机器上,〜95ms是在保存代码开始之前验证代码是否执行之间的魔数(Magic Number)。取决于用户的计算机速度,它可能更高或更低。

有谁知道如何处理这种情况?一位同事建议在验证代码运行时使用信号量,并在保存代码中使用繁忙循环,直到信号量解锁为止-但我想避免在我的代码中使用任何形式的繁忙循环。

最佳答案

使用信号量(我们称它为StillNeedsValidating)。如果SaveForm函数看到StillNeedsValidating信号量已启动,请它激活它自己的第二个信号量(在这里将其称为FormNeedsSaving)并返回。验证函数完成后,如果FormNeedsSaving信号量打开,它将自行调用SaveForm函数。

用jankcode;

function UserInputChanged(control) {
    StillNeedsValidating = true;
    // do validation
    StillNeedsValidating = false;
    if (FormNeedsSaving) saveForm();
}

function SaveForm() {
    if (StillNeedsValidating) { FormNeedsSaving=true; return; }
    // call web service to save value
    FormNeedsSaving = false;
}

08-15 20:45