你还没有展示你是如何调用这些函数的,但如果它归结为onbeforeunload 或onunload 处理程序,恐怕你不能按照你的要求去做。这些都不能等待异步过程完成,也不能取消(用户除外)。 见下文,你可以用这些做点什么链接。
另外:在最近的 jQuery 中,没有办法使 $.Deferred 的回调同步到您的 then(done 等)处理程序(即使在旧 jQuery 中,如果 Deferred在您致电then 等之前尚未解决)。 jQuery 的Deferred 已更新为与Promises/A+ specification 一致,这要求对then 的调用和类似的回调必须是异步的。 (在更新为符合该规范之前,Deferred 是混乱的:如果已经解决,它会同步调用回调,但如果还没有,那么它当然是异步的。Promises/A+ 没有不允许这种混乱的行为。)
您现在已经说过要像这样调用这些函数:
<a href="link" onclick="saveOnNavigation">link</a>
我认为它必须如下,()
<a href="link" onclick="saveOnNavigation()">link</a>
如果您可以将其更改为:
<a href="link" onclick="return saveOnNavigation(this, event)">link</a>
然后您可以继续,在该处理程序中进行异步操作,取消默认导航,然后在完成后导航:
function saveOnNavigation(link, event) {
// Start the async operation
startAsynchronousOperation().then(function(saved) {
// Now it's finished (later)
if (saved){
// All good, do the navigation
console.log("saved and navigate to next page.");
location = link.href;
} else {
// Not good, don't navigate
console.log("failed to save. Staying on page");
}
});
// Cancel the click (belt-and-braces)
if (event.preventDefault) {
event.preventDefault();
}
return false;
}
实时示例:
var clicks = 0;
function startAsynchronousOperation() {
var d = $.Deferred();
setTimeout(function() { // Emulate an async op
if (++clicks == 1) {
d.resolve(false); // disallow
} else {
d.resolve(true); // allow
}
}, 500);
return d.promise();
}
function saveOnNavigation(link, event) {
// Start the async operation
startAsynchronousOperation().then(function(saved) {
// Now it's finished (later)
if (saved) {
// All good, do the navigation
console.log("saved and navigate to next page.");
location = link.href;
} else {
// Not good, don't navigate
console.log("failed to save. Staying on page");
}
});
// Cancel the click (belt-and-braces)
if (event.preventDefault) {
event.preventDefault();
}
return false;
}
<a href="http://example.com" onclick="return saveOnNavigation(this, event)">The first click on this link will be stopped; the second one will be allowed.</a>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
注意:如果用户右键单击链接并从菜单中选择其中一个选项(例如“在新选项卡中打开”),您的 onclick 处理程序将不会被调用上面的代码都不起作用。但我猜,既然这不会使当前窗口离开页面,那没关系。
如果您不能更改页面的标记,我们仍然可以做到。 :-) 我们只需要在页面加载后运行一些代码,将那些老式的属性样式事件处理程序转换为现代事件处理程序:
$('a[onclick*="saveOnNavigation"]')
.attr("onclick", "")
.on("click", saveOnNavigation);
...我们将saveOnNavigation 更改为:
function saveOnNavigation(event) {
var link = this;
// Cancel the click
event.preventDefault();
// Start the async operation
startAsynchronousOperation().then(function(saved) {
// Now it's finished (later)
if (saved) {
// All good, do the navigation
console.log("saved and navigate to next page.");
location = link.href;
} else {
// Not good, don't navigate
console.log("failed to save. Staying on page");
}
});
}
例子:
var clicks = 0;
function startAsynchronousOperation() {
var d = $.Deferred();
setTimeout(function() { // Emulate an async op
if (++clicks == 1) {
d.resolve(false); // disallow
} else {
d.resolve(true); // allow
}
}, 500);
return d.promise();
}
function saveOnNavigation(event) {
var link = this;
// Cancel the click
event.preventDefault();
// Start the async operation
startAsynchronousOperation().then(function(saved) {
// Now it's finished (later)
if (saved) {
// All good, do the navigation
console.log("saved and navigate to next page.");
location = link.href;
} else {
// Not good, don't navigate
console.log("failed to save. Staying on page");
}
});
}
$(document).ready(function() { // Don't need this if the script tag is at the end, just before </body>
$('a[onclick*="saveOnNavigation"]')
.attr("onclick", "")
.on("click", saveOnNavigation);
});
<a href="http://example.com" onclick="saveOnNavigation()">The first click on this link will be stopped; the second one will be allowed.</a>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>