AJAX - 运行 同时发出两个请求,但其中一个以一定间隔重复
AJAX - run two requests at same time, but one of them repeatedly with some interval
我想实现以下功能:
第一个 AJAX 请求将数据导入 MS SQL 数据库。数据库中有一个 table,其中包含一些有关导入的数据(总记录、已处理记录、开始时间等)。 table 中的数据在导入过程中不断更新。
例如,第二个 AJAX 请求应该每 5 秒从 table 获取更新的数据,并以某种通知的形式将其显示在页面上。
我面临的问题如下:第一个请求开始,执行它需要几分钟。与此同时,第二个请求以 5 秒的间隔被调用,但是所有的请求直到第一个请求完成后才被执行,它们都在排队并且状态为 "Pending"。我不知道这是怎么回事。看起来我无法在第一个 TTFB 期间启动第二个 AJAX 请求。
我也尝试过使用 jQuery.when() 和 jQuery.then(),但我不明白如何在 jQuery.when() 内使用间隔进行 AJAX 调用。有什么办法可以实现我想要的功能吗?
这是我的代码,单击导入按钮时会调用 RunImport 函数:
var resultCheck, resultRun, intervalId = 0;
$(document).ready(function () {
CheckActiveImports();
});
function CheckActiveImports() {
var jqXHR = $.ajax({
url: "exhaust.aspx/GetRunningImports",
async:true,
type: "GET",
contentType: "application/json; charset=utf-8",
dataType: "json",
beforeSend: function(){
$('#output').html("Checking for running imports...");
},
success: OnCheckSuccess,
failure: function (result) {
resultCheck = "Failure: " + result.responseText;
},
error: function (result) {
resultCheck = "Error: " + result.responseText;
},
complete: function () {
$('#output').html(resultCheck);
}
});
return jqXHR;
}
function OnCheckSuccess(result)
{
var data = result.d; //JSON.parse(result).d;
if (data.length) {
var res = "";
for (var x in data) {
var format = 'Job running: ' + data[x].JobType + '. ' + data[x].Counter + ' of ' + data[x].Total + ' records processed<br /> \
Speed: ' + data[x].Speed + ' records per minute. \
Estimated time of completion: ' + data[x].EstTime + '.';
res += format;
}
resultCheck = res;
}
else {
resultCheck = 'Currently there are no jobs running.';
}
}
function RunImport()
{
intervalId = window.setInterval(CheckActiveImports, 5000);
RunImportAjax();
}
function RunImportDeferred() {
var RunImportXHR = RunImportAjax(),
CheckImportXHR = CheckActiveImports();
$.when(RunImportXHR, CheckImportXHR).then(function () {
$('#output').html(resultCheck);
$('#output2').html(resultRun);
});
}
function RunImportAjax() {
var jqXHR = $.ajax({
url: "exhaust.aspx/RunImport",
async:true,
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
beforeSend: function () {
$('#output2').html("Running import...");
},
success: function (result) {
window.clearInterval(intervalId);
var data = result.d;
if (data.length) {
var res = "";
for (var x in data) {
var format = 'Job finished: ' + data[x].JobType + '. ' + data[x].Counter + ' records processed.<br />';
res += format;
}
resultRun = res;
}
},
failure: function (result) {
resultRun = "Failure: " + result.responseText;
},
error: function (result) {
resultRun = "Error: " + result.responseText;
},
complete: function () {
$('#output2').html(resultRun);
}
});
return jqXHR;
}
这可以通过 "disposer pattern" 来完成,其中 "resource"(window.setInterval()
)在启动导入时建立,并在导入的承诺结算时处置。
对外部变量的需求和对 RunImportDeferred()
的需求一样消失了。 RunImportAjax()
可以重命名为 RunImport()
或类似名称。 CheckActiveImports()
和 OnCheckSuccess()
可以保持原样。
function RunImport() {
$('#output2').html("Running import...");
var intervalId = window.setInterval(CheckActiveImports, 5000); // establish a progress observer
return $.ajax({
url: 'exhaust.aspx/RunImport',
async:true,
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json'
}).then(function (result) {
var data = result.d,
res;
if (data.length) {
res = jQuery.map(data, function(item) {
return 'Job finished: ' + item.JobType + '. ' + item.Counter + ' records processed.';
}).join('<br />');
} else {
res = '';
}
$('#output2').html(res);
return result; // in case RunImport's caller is interested.
}, function(error) {
$('#output2').html(error.message);
}).always(function() {
window.clearInterval(intervalId); // dispose of the progress observer
});
}
如果服务器有能力处理导入和进度请求,那么这应该可行。
进度观察器可以写得更好,不涉及 window.setInterval()
但这可能是一个单独的问题。
编辑:没有 setInterval()
的定期观察者
没有 setInterval()
的周期性观察者相当简单,停止它比原来的 clearInterval()
更好,方法是(可选)中止任何未决的 ajax。
在下面的方法中,:
CheckActiveImports()
(和 OnCheckSuccess()
)的详细行为通过传递几个参数来控制。
CheckActiveImports()
returns 一个在 RunImport()
. 中用作处理器的停止函数
在caller中,可以调用返回的disposer函数,如下:
dispose()
: 停止进一步 ajax 调用。
dispose(true)
:中止挂起的 ajax 调用并停止进一步的 ajax 调用。
你可能想要后者。
function CheckActiveImports($container, interval, initMessage, finalMessage) {
$container.html(initMessage || '');
var jqXHR = null,
timeoutRef = setTimeout(check, interval),
_recurse_ = true;
function check() {
jqXHR = $.ajax({
url: "exhaust.aspx/GetRunningImports",
async: true,
type: "GET",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: OnCheckSuccess.bind(null, $container),
error: function (result) {
$container.text("Error: " + result.responseText);
},
complete: function() {
if(_recurse_) {
timeoutRef = setTimeout(check, interval); // recursive call
}
}
});
}
return function(abort) {
if(abort && jqXHR) jqXHR.abort();
clearTimeout(timeoutRef);
_recurse_ = false;
$container.text(finalMessage || '');
};
}
function OnCheckSuccess($container, result) {
var data = result.d, //JSON.parse(result).d
res;
if(data.length) {
res = jQuery.map(data, function(item) {
return 'Job running: ' + item.JobType + '. ' + item.Counter + ' of ' + item.Total + ' records processed<br /> \
Speed: ' + item.Speed + ' records per minute. \
Estimated time of completion: ' + item.EstTime + '.';
}).join('<br/>');
} else {
res = 'Currently there are no jobs running.';
}
$container.text(res);
}
function RunImport() {
var $container = $('#output2').html("Running import...");
var dispose = CheckActiveImports($('#output'), 5000, 'Checking for running imports...', ''); // start the progress observer
return $.ajax({
url: 'exhaust.aspx/RunImport',
async:true,
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json'
}).then(function (result) {
var data = result.d,
res;
if (data.length) {
res = jQuery.map(data, function(item) {
return 'Job finished: ' + item.JobType + '. ' + item.Counter + ' records processed.';
}).join('<br />');
} else {
res = '';
}
$container.html(res);
return result; // in case RunImport's caller is interested.
}, function(error) {
$container.html(error.message);
}).always(function() {
dispose(true); // dispose of the progress observer and abort any pending ajax.
});
}
我想实现以下功能: 第一个 AJAX 请求将数据导入 MS SQL 数据库。数据库中有一个 table,其中包含一些有关导入的数据(总记录、已处理记录、开始时间等)。 table 中的数据在导入过程中不断更新。
例如,第二个 AJAX 请求应该每 5 秒从 table 获取更新的数据,并以某种通知的形式将其显示在页面上。
我面临的问题如下:第一个请求开始,执行它需要几分钟。与此同时,第二个请求以 5 秒的间隔被调用,但是所有的请求直到第一个请求完成后才被执行,它们都在排队并且状态为 "Pending"。我不知道这是怎么回事。看起来我无法在第一个 TTFB 期间启动第二个 AJAX 请求。
我也尝试过使用 jQuery.when() 和 jQuery.then(),但我不明白如何在 jQuery.when() 内使用间隔进行 AJAX 调用。有什么办法可以实现我想要的功能吗?
这是我的代码,单击导入按钮时会调用 RunImport 函数:
var resultCheck, resultRun, intervalId = 0;
$(document).ready(function () {
CheckActiveImports();
});
function CheckActiveImports() {
var jqXHR = $.ajax({
url: "exhaust.aspx/GetRunningImports",
async:true,
type: "GET",
contentType: "application/json; charset=utf-8",
dataType: "json",
beforeSend: function(){
$('#output').html("Checking for running imports...");
},
success: OnCheckSuccess,
failure: function (result) {
resultCheck = "Failure: " + result.responseText;
},
error: function (result) {
resultCheck = "Error: " + result.responseText;
},
complete: function () {
$('#output').html(resultCheck);
}
});
return jqXHR;
}
function OnCheckSuccess(result)
{
var data = result.d; //JSON.parse(result).d;
if (data.length) {
var res = "";
for (var x in data) {
var format = 'Job running: ' + data[x].JobType + '. ' + data[x].Counter + ' of ' + data[x].Total + ' records processed<br /> \
Speed: ' + data[x].Speed + ' records per minute. \
Estimated time of completion: ' + data[x].EstTime + '.';
res += format;
}
resultCheck = res;
}
else {
resultCheck = 'Currently there are no jobs running.';
}
}
function RunImport()
{
intervalId = window.setInterval(CheckActiveImports, 5000);
RunImportAjax();
}
function RunImportDeferred() {
var RunImportXHR = RunImportAjax(),
CheckImportXHR = CheckActiveImports();
$.when(RunImportXHR, CheckImportXHR).then(function () {
$('#output').html(resultCheck);
$('#output2').html(resultRun);
});
}
function RunImportAjax() {
var jqXHR = $.ajax({
url: "exhaust.aspx/RunImport",
async:true,
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
beforeSend: function () {
$('#output2').html("Running import...");
},
success: function (result) {
window.clearInterval(intervalId);
var data = result.d;
if (data.length) {
var res = "";
for (var x in data) {
var format = 'Job finished: ' + data[x].JobType + '. ' + data[x].Counter + ' records processed.<br />';
res += format;
}
resultRun = res;
}
},
failure: function (result) {
resultRun = "Failure: " + result.responseText;
},
error: function (result) {
resultRun = "Error: " + result.responseText;
},
complete: function () {
$('#output2').html(resultRun);
}
});
return jqXHR;
}
这可以通过 "disposer pattern" 来完成,其中 "resource"(window.setInterval()
)在启动导入时建立,并在导入的承诺结算时处置。
对外部变量的需求和对 RunImportDeferred()
的需求一样消失了。 RunImportAjax()
可以重命名为 RunImport()
或类似名称。 CheckActiveImports()
和 OnCheckSuccess()
可以保持原样。
function RunImport() {
$('#output2').html("Running import...");
var intervalId = window.setInterval(CheckActiveImports, 5000); // establish a progress observer
return $.ajax({
url: 'exhaust.aspx/RunImport',
async:true,
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json'
}).then(function (result) {
var data = result.d,
res;
if (data.length) {
res = jQuery.map(data, function(item) {
return 'Job finished: ' + item.JobType + '. ' + item.Counter + ' records processed.';
}).join('<br />');
} else {
res = '';
}
$('#output2').html(res);
return result; // in case RunImport's caller is interested.
}, function(error) {
$('#output2').html(error.message);
}).always(function() {
window.clearInterval(intervalId); // dispose of the progress observer
});
}
如果服务器有能力处理导入和进度请求,那么这应该可行。
进度观察器可以写得更好,不涉及 window.setInterval()
但这可能是一个单独的问题。
编辑:没有 setInterval()
的定期观察者没有 setInterval()
的周期性观察者相当简单,停止它比原来的 clearInterval()
更好,方法是(可选)中止任何未决的 ajax。
在下面的方法中,:
CheckActiveImports()
(和OnCheckSuccess()
)的详细行为通过传递几个参数来控制。CheckActiveImports()
returns 一个在RunImport()
. 中用作处理器的停止函数
在caller中,可以调用返回的disposer函数,如下:
dispose()
: 停止进一步 ajax 调用。dispose(true)
:中止挂起的 ajax 调用并停止进一步的 ajax 调用。
你可能想要后者。
function CheckActiveImports($container, interval, initMessage, finalMessage) {
$container.html(initMessage || '');
var jqXHR = null,
timeoutRef = setTimeout(check, interval),
_recurse_ = true;
function check() {
jqXHR = $.ajax({
url: "exhaust.aspx/GetRunningImports",
async: true,
type: "GET",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: OnCheckSuccess.bind(null, $container),
error: function (result) {
$container.text("Error: " + result.responseText);
},
complete: function() {
if(_recurse_) {
timeoutRef = setTimeout(check, interval); // recursive call
}
}
});
}
return function(abort) {
if(abort && jqXHR) jqXHR.abort();
clearTimeout(timeoutRef);
_recurse_ = false;
$container.text(finalMessage || '');
};
}
function OnCheckSuccess($container, result) {
var data = result.d, //JSON.parse(result).d
res;
if(data.length) {
res = jQuery.map(data, function(item) {
return 'Job running: ' + item.JobType + '. ' + item.Counter + ' of ' + item.Total + ' records processed<br /> \
Speed: ' + item.Speed + ' records per minute. \
Estimated time of completion: ' + item.EstTime + '.';
}).join('<br/>');
} else {
res = 'Currently there are no jobs running.';
}
$container.text(res);
}
function RunImport() {
var $container = $('#output2').html("Running import...");
var dispose = CheckActiveImports($('#output'), 5000, 'Checking for running imports...', ''); // start the progress observer
return $.ajax({
url: 'exhaust.aspx/RunImport',
async:true,
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json'
}).then(function (result) {
var data = result.d,
res;
if (data.length) {
res = jQuery.map(data, function(item) {
return 'Job finished: ' + item.JobType + '. ' + item.Counter + ' records processed.';
}).join('<br />');
} else {
res = '';
}
$container.html(res);
return result; // in case RunImport's caller is interested.
}, function(error) {
$container.html(error.message);
}).always(function() {
dispose(true); // dispose of the progress observer and abort any pending ajax.
});
}