仅当上一个函数调用中没有另一个 AJAX 请求正在进行时,才执行 AJAX 调用



我已经登陆了一个新的混乱的代码库,没有任何可用的测试,我在这个问题上挣扎了很长一段时间。我不能使用任何ES6代码,只能使用普通的原版JS和jQuery。

上下文:在网页上有几对输入,来自该对输入的第一个输入触发模糊firstFunction(),第二个输入也触发模糊事件的secondFunction()。从下面的示例代码中可以看出,每个函数随后调用另一个函数,ajaxFunction()执行 AJAX 请求。

目标:我希望只有在上一个函数调用没有另一个 AJAX 请求正在进行时才能够调用ajaxFunction()。问题是,当它第一次在一对输入上运行时,会在数据库中创建一个新行,并且请求返回该行的 ID。因此,当第二次调用它时,由于 ID 的原因,它将是数据库中的 UPDATE 而不是 INSERT。如果来自该对的第二个调用在第一个调用完成之前运行,则我最终会在数据库中有两个不同的行,这是不希望的。

示例:如果用户在第一个输入中输入了一些文本,则firstFunction()在模糊时触发,然后他快速移动到第二个输入并输入某些内容,以便在模糊时触发secondFunction(),但可能是来自firstFunction()调用的 AJAX 请求尚未完成。因此,仅当来自firstFunction()的 AJAX 调用已完成时,才应启动来自secondFunction()的 AJAX 调用。相同的逻辑适用于用户开始键入第二个输入和第一个输入的情况。

注意:这不是页面上唯一的 AJAX 请求,还有其他几个请求。

我做了一些研究,我觉得$.when()是我需要的,但是当涉及到将其集成到这个逻辑中时,它击败了我。我也想过$.active但它并没有真正的帮助。

function firstFunction() {
// Some logic goes here then we call the AJAX function. 
ajaxFunction(1, 2, 3);
}
function secondFunction() {
// Some logic goes here then we call the AJAX function. 
ajaxFunction(4, 5, 6);
}
function ajaxFunction(param1, param2, param3) {
$.ajax({
method: "POST",
url: "https://website.localhost",
data: { 
param1: param1
param2: param2
param3: param3
}
}).done(function() {
console.log('Done!');
});
}

由于您的范围内有可用的 jQuery,我将使用队列功能来涵盖此用例。其背后的基本思想是利用此可用功能并将您的 XHR 请求组织到 FIFO 行中。

@gnarf对这个答案进行了很好的解释。

这是一种快速的队列方法,有一些方法可以使其更干净,但这是基本概念

function firstFunction() {
addToQueue({
param1: 1,
param1: 2,
param1: 3
});
}
function secondFunction() {
addToQueue({
param1: 1,
param1: 2,
param1: 3
});
}

var activeQueue = []
var activeRequest = false
function addToQueue(data) {
// Add item to the queue of things needing to run
activeQueue.push(data);
// if the request is not active than run it
if (!activeRequest) {
executeQueue()
}
}
function executeQueue() {
// if nothing to run, exit
if (!activeQueue.length) return
// set the request is active
activeRequest = true
// get the data for this request
var data = activeQueue.shift()
// make the call
$.ajax({
method: "POST",
url: "https://website.localhost",
data: data
}).done(function() {
console.log('Done!');
// mark call is done
activeRequest = activeQueue.length > 0
// run it again
executeQueue()
});
}

如果你不想允许制作另一个 ajax,如果一个已经在进行中并且还没有提交(有错误或成功(,那么只需创建一个全局布尔变量,例如:

var ajaxInProgress = false.

您可以在ajaxFunction中将其设置为 true,并在 ajax 完成时将其设置为 false。然后你把你的ajax调用放在一个if(!ajaxInProgress) {...}

这样,如果已经进行了第二个 ajax 调用,则不会进行第二次 ajax 调用。

我怀疑你想把你的ajax调用放在队列中,这样如果你做这样的事情:

firstFunction();
secondFunction();

你的第二个函数将发送 ajax,但只有在第一个函数完成后。为了实现这一点,我会为您的代码编写一个简单的队列:

var queue = [];
var ajaxInProgress = false;
function ajaxFunction(param1, param2, param3) {
if (!ajaxInProgress) {
ajaxInProgress = true;
$.ajax({
method: "POST",
url: "https://website.localhost",
data: {
param1: param1,
param2: param2,
param3: param3
}
}).done(function () {
console.log('Done!');
ajaxInProgress = false;
executeNextAjaxInQueue();
});
} else {
ajaxInProgress.push([param1, param2, param3]);
}
}
function executeNextAjaxInQueue(ajaxParams) {
if (queue.length === 0) {
return;
}
var params = queue.shift();
ajaxFunction(params[0], params[1], params[2]);
}

取决于你想要什么。

  1. 如果当 ajax 请求已在进行中时完全忽略所有 ajax 请求,则:
var ajaxFuntion = (function() {
var inFlight = null;
return function(param1, param2, param3) {
if(!inFlight) {
inFlight = $.ajax({
'method': "POST",
'url': "https://website.localhost",
'data': { 
'param1': param1,
'param2': param2,
'param3': param3
}
}).done(function(val) {
inFlight = null;
});
};
return inFlight;
};
})();
  1. 如果要将 ajax 请求排队到之前排队的任何请求(其中任何一个可能正在进行(,则:
var ajaxFuntion = (function() {
var inFlight = jQuery.when(); // dummy starter promise.
return function(param1, param2, param3) {
inFlight = inflight.then(function() {
return $.ajax({
'method': "POST",
'url': "https://website.localhost",
'data': { 
'param1': param1,
'param2': param2,
'param3': param3
}
});
};
return inFlight;
});
})();

如您所见,这两个版本都涉及返回函数的 IIFE。

通过使用 IIFE,inFlight变量是"自包含的",避免了在与ajaxFuntion或更高范围相同的范围内使用另一个成员。

在第二个版本中,请注意排队非常简单,因为jQuery.ajax()返回一个承诺,允许通过任意次数链接.then().then().then()来形成队列。

最新更新