尽管我一直在处理 standard [1]了几个月,但Ajax代码中的一个简单错误使我今天意识到,还有很多我还没有掌握,我觉得我需要对此事进行澄清。
我正在编写一个管理界面,以从用MVC 5编写的Web应用程序中添加和删除用户。我有这段代码调用一个操作方法(最终在SQL数据库上执行存储过程),然后删除显示的DOM元素用户的详细信息:
$.ajax({
url: "RemoveUser",
type: "POST",
data: {
userID: userID
}
}).done(
$('.row').filter(function () {
if ($(this).data()["userID"] === userID) {
return true;
}
}).remove()
);
在测试时,我看到删除DOM元素后触发了操作方法。在查看ajax官方文档时,我意识到done
回调中的代码应该包装在function () { ... }
块中。我相应地更改了代码
$.ajax({
url: "RemoveUser",
type: "POST",
data: {
userID: userID
}
}).done(function () {
$('.row').filter(function () {
if ($(this).data()["userID"] === userID) {
return true;
}
}).remove();
});
现在一切都按预期的顺序进行。
任何人都可以阐明为什么错包导致了预期行为的改变吗?
[1]按标准的意思是简单的GET
或POST
操作,它们返回DOM元素或基本数据。
答案 0 :(得分:4)
任何人都可以阐明为什么错包导致了预期行为的改变吗?
因此,
one(two());
调用 two
,然后使用one
的返回值调用two
。但这:
one(function() {
two();
});
创建一个函数并使用它调用one
。仅当one
中的代码调用该函数时,该函数才会运行。
one
是$.ajax
。 two
是您的filter
/ remove
代码。
答案 1 :(得分:2)
这是因为done
的参数应该是一个函数。实际的函数对象(请记住,函数是Javascript中的“第一类”,这意味着一个函数可以传递给其他函数,或者像其他任何值一样从函数返回)-然后在Ajax响应为收到。
此外,像大多数语言一样,以更复杂的表达式形式给出的函数参数需要在调用函数之前进行实际求值。当您这样做时,大概不会让您感到惊讶:
var a = "hello";
var b = "world;
console.log(a + " " + b);
JS引擎首先评估a + " " + b
表达式以获得字符串“ hello world”,然后将其输入console.log
中。
好吧,在第一个示例中发生的事情完全相同:
$.ajax({
url: "RemoveUser",
type: "POST",
data: {
userID: userID
}
}).done(
$('.row').filter(function () {
if ($(this).data()["userID"] === userID) {
return true;
}
}).remove()
);
这里必须首先计算done
的参数-这意味着将执行所有带有.filter
和.remove
的代码。当脚本首次加载并运行时,这种情况立即发生。 (它不会产生函数-可以说这会导致错误,但是JS是一种动态类型的语言,并且众所周知它在不引发早期错误的情况下放宽了它的允许范围。我不在这里进行讨论关于这是好事还是坏事-无论您是否喜欢,它都会发生。)
在第二个示例中,使用“包装函数”:
$.ajax({
url: "RemoveUser",
type: "POST",
data: {
userID: userID
}
}).done(function () {
$('.row').filter(function () {
if ($(this).data()["userID"] === userID) {
return true;
}
}).remove();
});
不同之处在于,实际上是传入了一个函数值(因为API需要正常工作),该函数尚未执行。函数参数是“回调”,将在Ajax结束时执行。该参数仍会事先被“评估”,因为(我认为)该函数对象是以某种方式在内部创建的-但其中的代码未执行。 jQuery的$.ajax
仅接受该函数参数并在适当的时候执行它(“回调”)。
答案 2 :(得分:0)
要添加到TJ提到的内容中,这就是回调的工作方式。假设您已经编写了函数function done(argument)
。可以说argument
是我们作为参数传递的函数(回调函数)。现在,如果要执行argument
,则必须在函数定义中包含function done(argument){ argument(); }
。在您的情况下,argument
是
function () {
$('.row').filter(function () {
if ($(this).data()["userID"] === userID) {
return true;
}
}).remove();
}
因此,如果删除函数包装器,则主体将在预期的时候不执行。 我希望这是有道理的。如果您对此有任何疑问,请告诉我。