Javascript AJAX调用在服务器端的执行顺序与在客户端的调用顺序不同

Javascript AJAX调用在服务器端的执行顺序与在客户端的调用顺序不同,javascript,ajax,asp.net-mvc,Javascript,Ajax,Asp.net Mvc,我有一个ASP.NET MVC应用程序,在视图中具有以下javascript函数: function OnAmountChanged(s, fieldName, keyValue, url) { console.log("Get Number: " + s.GetNumber()); console.log(" "); $.ajax({ type: "POST", url: url, data

我有一个ASP.NET MVC应用程序,在视图中具有以下javascript函数:

function OnAmountChanged(s, fieldName, keyValue, url) {
    console.log("Get Number: " + s.GetNumber());
    console.log(" ");
        $.ajax({
            type: "POST",
            url: url,
            data: { key: keyValue, field: fieldName, value: s.GetNumber() },
            success: function () {
                reloadShoppingCartSummary();
            }
        });
}
通过向上/向下按钮,我可以增加/减少每次单击时调用此函数的字段数。 通过console.log,我可以看到JavaScript函数的调用顺序是正确的(我更改数值的顺序)。 但通过在服务器端进行调试,我注意到它执行调用的顺序是不同的。 什么会导致这个问题?
我该如何解决这个问题呢?

这一点都不奇怪,也不是你所能期望的。如果您希望按特定顺序处理请求,则必须发送一个请求,等待其响应,然后发送下一个请求。你不能只发送所有的邮件,然后期望它们按照特定的顺序进行处理

在您的特定情况下,如果一个请求是“正在进行中”,您必须禁用该按钮,或者将下一个请求排队,并在前一个请求完成时播放它

对于如何发送数据,也有各种策略可以防止、适应或检测无序问题,但使用哪种策略以及如何发送取决于您发送的特定数据以及它在客户端和服务器端的工作方式

有许多可能的编码策略来处理这个问题。这里有一种方法,可以在处理另一个请求时对传入的任何请求进行排队,强制服务器按顺序处理它们:

var changeQueue = [];
changeQueue.inProcess = false;
function OnAmountChanged(s, fieldName, keyValue, url) {
    // if already processing a request, then queue this one until the current request is done
    if (changeQueue.inProcess) {
        changeQueue.push({s:s, fieldName: fieldName, keyValue: keyValue, url: url});
    } else {
        changeQueue.inProcess = true;
        console.log("Get Number: " + s.GetNumber());
        console.log(" ");

            $.ajax({
                type: "POST",
                url: url,
                data: { key: keyValue, field: fieldName, value: s.GetNumber() },
                success: function () {
                    reloadShoppingCartSummary();
                }, complete: function() {
                    changeQueue.inProcess = false;
                    if (changeQueue.length) {
                        var next = changeQueue.shift();
                        OnAmountChanged(next.s, next.fieldName, next.keyValue, next.url);
                    }
                }
            });
        }
}
仅供参考,我想我们可能会得到为我们做排队工作的承诺,但我正在制定一些细节。有一个想法正在酝酿中:。如果您快速多次按下按钮,您可以看到它将按顺序排列并处理这些按钮


下面是通用promise序列化程序的具体想法:

// utility function that works kind of like `.bind()`
// except that it works only on functions that return a promise
// and it forces serialization whenever the returned function is called
// no matter how many times it is called in a row
function bindSingle(fn) {
    var p = Promise.resolve();

    return function(/* args */) {
        var args = Array.prototype.slice.call(arguments, 0);

        function next() {
            return fn.apply(null, args);
        }

        p = p.then(next, next);
        return p;
    }
}

function OnAmountChanged(s, fieldName, keyValue, url) {
    console.log("Get Number: " + s.GetNumber());
    console.log(" ");
    return $.ajax({
        type: "POST",
        url: url,
        data: { key: keyValue, field: fieldName, value: s.GetNumber() }
    }).then(reloadShoppingCartSummary);
}

var OnAmountChangedSingle = bindSingle(OnAmountChanged);

因此,要使用此代码,您需要将
OnAmountChangedSingle
传递给事件处理程序,而不是
OnAmountChanged
,这将强制序列化。

这一点都不奇怪,也不是您所期望的。如果您希望按特定顺序处理请求,则必须发送一个请求,等待其响应,然后发送下一个请求。你不能只发送所有的邮件,然后期望它们按照特定的顺序进行处理

在您的特定情况下,如果一个请求是“正在进行中”,您必须禁用该按钮,或者将下一个请求排队,并在前一个请求完成时播放它

对于如何发送数据,也有各种策略可以防止、适应或检测无序问题,但使用哪种策略以及如何发送取决于您发送的特定数据以及它在客户端和服务器端的工作方式

有许多可能的编码策略来处理这个问题。这里有一种方法,可以在处理另一个请求时对传入的任何请求进行排队,强制服务器按顺序处理它们:

var changeQueue = [];
changeQueue.inProcess = false;
function OnAmountChanged(s, fieldName, keyValue, url) {
    // if already processing a request, then queue this one until the current request is done
    if (changeQueue.inProcess) {
        changeQueue.push({s:s, fieldName: fieldName, keyValue: keyValue, url: url});
    } else {
        changeQueue.inProcess = true;
        console.log("Get Number: " + s.GetNumber());
        console.log(" ");

            $.ajax({
                type: "POST",
                url: url,
                data: { key: keyValue, field: fieldName, value: s.GetNumber() },
                success: function () {
                    reloadShoppingCartSummary();
                }, complete: function() {
                    changeQueue.inProcess = false;
                    if (changeQueue.length) {
                        var next = changeQueue.shift();
                        OnAmountChanged(next.s, next.fieldName, next.keyValue, next.url);
                    }
                }
            });
        }
}
仅供参考,我想我们可能会得到为我们做排队工作的承诺,但我正在制定一些细节。有一个想法正在酝酿中:。如果您快速多次按下按钮,您可以看到它将按顺序排列并处理这些按钮


下面是通用promise序列化程序的具体想法:

// utility function that works kind of like `.bind()`
// except that it works only on functions that return a promise
// and it forces serialization whenever the returned function is called
// no matter how many times it is called in a row
function bindSingle(fn) {
    var p = Promise.resolve();

    return function(/* args */) {
        var args = Array.prototype.slice.call(arguments, 0);

        function next() {
            return fn.apply(null, args);
        }

        p = p.then(next, next);
        return p;
    }
}

function OnAmountChanged(s, fieldName, keyValue, url) {
    console.log("Get Number: " + s.GetNumber());
    console.log(" ");
    return $.ajax({
        type: "POST",
        url: url,
        data: { key: keyValue, field: fieldName, value: s.GetNumber() }
    }).then(reloadShoppingCartSummary);
}

var OnAmountChangedSingle = bindSingle(OnAmountChanged);

因此,要使用此代码,您需要将
OnAmountChangedSingle
传递给事件处理程序,而不是
OnAmountChanged
,这将强制序列化。

不按顺序执行。这就是AJAX的魅力所在。它是异步使用的。您可以发送带有AJAX请求的
计数器
,并在服务器端对请求进行排队,直到之前的所有请求都未被处理。
未按顺序执行
。这就是AJAX的魅力所在。它是异步使用的。您可以发送一个带有AJAX请求的
计数器
,并在服务器端对请求进行排队,直到之前的所有请求都未被处理。添加了一个使用承诺的自动排序器。我将得到一个例外:“承诺”不是defined@Palmi-您在什么环境下运行它?IE11。我刚刚看到IE不支持Promise.resolve()。而且您的第一个建议也没有按预期效果。我添加了一个console.log(“push:+s.GetNumber());在push命令和console.log(“shift:+next.s.GetNumber())之前;在shift命令之后。这是更改字段值后的结果:push:44 push:43 push:42 push:41 push:40 push:39 shift:39 shift:39 shift:39 shift:39添加了一个使用承诺的自动序列器。我将得到一个例外:“承诺”不是defined@Palmi-您在什么环境下运行它?IE11。我刚刚看到IE不支持Promise.resolve()。而且您的第一个建议也没有按预期效果。我添加了一个console.log(“push:+s.GetNumber());在push命令和console.log(“shift:+next.s.GetNumber())之前;在shift命令之后。这是更改字段值后的结果:push:44 push:43 push:42 push:41 push:40 push:39 shift:39 shift:39 shift:39 shift:39 shift:39 shift:39 shift:39