Javascript Jquery何时和延迟对象,函数流中断
我使用$.when和.done来确保在保存数据后关闭窗口。但是,这似乎并不像预期的那样有效 工作流程是,用户单击“保存并关闭”按钮,首先保存数据,触发打印并关闭窗口。但保存数据和关闭窗口同时发生,导致打印失败 我已经读过关于什么时候…然后和推迟的对象。尝试在下面的代码中实现它,有时它可以工作,但大多数时候它会中断Javascript Jquery何时和延迟对象,函数流中断,javascript,jquery,jquery-deferred,.when,Javascript,Jquery,Jquery Deferred,.when,我使用$.when和.done来确保在保存数据后关闭窗口。但是,这似乎并不像预期的那样有效 工作流程是,用户单击“保存并关闭”按钮,首先保存数据,触发打印并关闭窗口。但保存数据和关闭窗口同时发生,导致打印失败 我已经读过关于什么时候…然后和推迟的对象。尝试在下面的代码中实现它,有时它可以工作,但大多数时候它会中断 $("#btnSaveAndClose").click(function (event) { $.when(zSaveSomeData()).done(function (va
$("#btnSaveAndClose").click(function (event) {
$.when(zSaveSomeData()).done(function (value) {
zCloseMyWindow();
});
});
function zSaveSomeData() {
return zSaveMasterData(masterdata, function () {
return zSaveDetailData();
});
};
function zSaveMasterData(masterdata, fnAfterSave) {
return $.ajax({
type: 'POST',
contentType: 'application/json',
url: '/api/masterdata/',
data: JSON.stringify(masterdata),
success: function (data) {
fnAfterSave();
}
});
};
function zSaveDetailData() {
var selectedDataGroups;
// some logic here
zSaveDetails(selectedDataGroups);
};
function zSaveDetails(selectedDataGroups) {
var deferred = $.Deferred();
$.ajax({
type: 'POST',
contentType: 'application/json',
url: '/api/detaildata/',
data: JSON.stringify(selectedDataGroups),
success: function (data) {
var printableGroupIDs = [];
$.each(data, function () {
if (this.IsPrintable)
printableGroupIDs.push(this.ID);
});
if (printableGroupIDs.length > 0) {
zPrintGroups(printableGroupIDs);
}
deferred.resolve('done');
}
});
zAuditSave();
return deferred.promise();
};
function zPrintGroups(newGroupIDs) {
// calls external program to print groups
};
function zCloseWindow() {
window.close();
};
function zAuditSave() {
$.ajax({
type: 'POST',
contentType: 'application/json',
url: '/api/audit'
success: function (data) {
}
});
};
唯一的问题是save调用内部的其他方法来处理相同的主数据和详细数据。还有几个ajax调用。一个不寻常的事情是,数据保存后,会调用VB代码,实际触发打印。我很困惑为什么要在其他方法执行之前关闭窗口。任何帮助都将不胜感激。这里的问题是您的代码不取决于
fnaturave()
何时完成
简短回答:不要混合使用成功
方法、回调
和承诺
——使用一种模式并坚持下去——最简单的模式是承诺
$("#btnSaveAndClose").click(function (event) {
zSaveSomeData().then(function() { zCloseMyWindow(); });
});
function zSaveSomeData() {
return zSaveMasterData(masterdata).then(function(data) { zSaveDetailData() });
};
function zSaveMasterData(masterdata) {
return $.ajax({
type: 'POST',
contentType: 'application/json',
url: '/api/masterdata/',
data: JSON.stringify(masterdata)
});
//remove success callback here as it breaks the chaining
};
您的问题似乎是在ajax
success
回调中执行异步操作。$.ajax
返回的承诺仍然会在收到响应后立即解析,并在异步zSaveDetailData()
完成之前执行done
回调
因此,要链接异步操作,请始终使用then
。即使在同步操作中也要使用它,因为它可以使顺序变得清晰
在处理承诺时,不要使用success
回调。你也是。您可能还想看一看,尤其是永远不要忘记从想要等待的异步函数返回
承诺
$("#btnSaveAndClose").click(function (event) {
zSaveSomeData().then(zCloseMyWindow);
});
function zSaveSomeData() {
return zSaveMasterData(masterdata).then(zSaveDetailData);
}
function zSaveMasterData(masterdata) {
return $.ajax({
type: 'POST',
contentType: 'application/json',
url: '/api/masterdata/',
data: JSON.stringify(masterdata),
});
}
function zSaveDetailData() {
var selectedDataGroups;
// some logic here
return zSaveDetails(selectedDataGroups);
// ^^^^^^
}
function zSaveOrderGroups(selectedDataGroups) {
return $.ajax({
// ^^^^^^
type: 'POST',
contentType: 'application/json',
url: '/api/detaildata/',
data: JSON.stringify(selectedDataGroups)
}).then(function(data) {
// ^^^^^^^^^^^^^^^^^^^^^^
var printableGroupIDs = [];
$.each(data, function () {
if (this.IsPrintable)
printableGroupIDs.push(this.ID);
});
if (printableGroupIDs.length > 0) {
return zPrintGroups(printableGroupIDs);
// ^^^^^^
}
}).then(zAuditSave);
// ^^^^^^^^^^^^^^^^^
}
function zPrintGroups(newGroupIDs) {
// calls external program to print groups
}
function zCloseWindow() {
window.close();
}
function zAuditSave() {
return $.ajax({
// ^^^^^^
type: 'POST',
contentType: 'application/json',
url: '/api/audit'
});
}
对我来说,代码被过度地划分为多个函数,有些函数只不过是为另一些函数做前置 我更愿意将click处理程序视为一个全面的主例程,它对三个函数进行排序,
zSaveMasterData()
,zSaveDetails()
和zAuditSave()
,然后关闭窗口。因此,单击处理程序将包含一些当前函数
$("#btnSaveAndClose").click(function(event) {
zSaveMasterData(masterdata).then(function() {
var selectedDataGroups;
/* some logic here */
var detailsSaved = zSaveDetails(selectedDataGroups).then(function(data) {
var printableGroupIDs = $.map(data, function (obj) {
return obj.IsPrintable ? obj.ID : null;
});
if (printableGroupIDs.length > 0) {
// calls external program to print groups
}
});
// Here, it is assumed that zSaveDetails() and zAuditSave() can be performed in parallel.
// If the calls need to be sequential, then the code will be slightly different.
return $.when(detailsSaved, zAuditSave());
}).then(function() {
window.close();
});
});
function zSaveMasterData(masterdata) {
return $.ajax({
type: 'POST',
url: '/api/masterdata/',
contentType: 'application/json',
data: JSON.stringify(masterdata),
});
};
function zSaveDetails(selectedDataGroups) {
return $.ajax({
type: 'POST',
contentType: 'application/json',
url: '/api/detaildata/',
data: JSON.stringify(selectedDataGroups)
});
};
function zAuditSave() {
return $.ajax({
type: 'POST',
contentType: 'application/json',
url: '/api/audit'
});
};
注意使用ajax调用的三个函数中的返回。这些返回对排序过程至关重要
一个潜在的更大的问题是如何从错误中恢复,这一点在问题(或本答案)中没有提到。据推测,如果保存顺序中途失败,数据库将不一致。最好放弃这种客户端排序方法,转而使用客户端视为单个操作的服务器端事务。
return zSaveDetailData();zCleanUp()代码>-等等什么?什么是zAuditSave()
?@Bergi,谢谢你指出这一点,实际上这段代码是我编辑时留下的。它不在那里。我添加了return to test,但确实清理了代码。zAuditSave()
是另一种调用webApi进行审计保存的方法。我也将添加该方法。我尝试重构代码,以仅使用一种模式,即承诺
。仍然在zPrintGroups()
之前调用zCloseWindow()
。我试着调试,发现控件点击了行returnzsavedetails(selectedDataGroups)代码>然后当我进入时,执行带有inzSaveDetails()
的ajax来保存数据,然后控件直接转到zCloseWindow()
并关闭窗口,因此zSaveDetails()
中的zPrintGroups()
方法永远不会被触发。也许你已经得到了然后(zCloseWindow())
而不是。然后(zCloseWindow)
?我交叉检查,它是zSaveSomeData()。然后(zCloseWindow)代码>。我还检查了所有其他的方法调用,它们看起来不错。你能在什么地方放一个演示吗?我很有信心这会奏效。当然,我会尝试创造一些可演示的东西。但不知道如何进行ajax调用。但是,让我试试。我认为你使用$.map
不起作用,though@Bergi,我的代码都没有经过测试,我很可能会犯错误。从内存来看,jQuery.map()
不同于Array.prototype.map()
,因为jQuery版本(a)在返回null时过滤掉一个元素,(b)返回一个jQuery包装的数组(因此需要.get())。是的,它应该被命名为concatMap
,因为它处理null
和数组值。但是实际上返回数组,而$(arr).map(fn)
返回jquery包装器。啊,好的,我应该首先查找它。文档还指出,“在函数中,此
引用全局(窗口)对象”。哎呀,编辑。谢谢你的帮助。