简体   繁体   English

Ajax完成回调时不等待不是函数

[英]Ajax done callback not waiting when is not a function

Prologue: 序幕:

Though I've been dealing with standard [1] Ajax calls for a couple months, a simple mistake in my code made me realize today that there's so much more I still haven't grasped, that I feel I need some clarification on the matter. 尽管我已经处理了几个月的标准 [1] Ajax调用,但是我的代码中有一个简单的错误,使我今天意识到,还有很多我还没有掌握,我觉得我需要对此事进行澄清。

The fact: 事实:

I'm writing an administration interface to add and remove users from a web application written in MVC 5. I had this code calling an action method (eventually executing a stored procedure on a SQL database) and then removing the DOM element showing user's details: 我正在编写一个管理界面,以从用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()
);

While testing, I saw that the action method was being triggered after the DOM element being removed. 在测试期间,我看到删除DOM元素触发了操作方法。 While reviewing the ajax official documentation, I realized that my code within the done callback should've been wrapped within a function () { ... } block. 在查阅ajax官方文档时,我意识到我应将done回调中的代码包装在function () { ... }块中。 I changed the code accordingly 我相应地更改了代码

$.ajax({
    url: "RemoveUser",
    type: "POST",
    data: {
        userID: userID
    }
}).done(function () {
    $('.row').filter(function () {
        if ($(this).data()["userID"] === userID) {
            return true;
        }
    }).remove();
});

and now it all works in the expected order. 现在一切都按预期的顺序进行了。

Can anyone please shed some light on why the missed wrapping caused this change in the expected behavior? 谁能说明为什么错包导致预期行为发生这种变化吗?


[1] by standard I mean simple GET or POST actions that return DOM elements or basic data. [1] 按照标准,我的意思是返回DOM元素或基本数据的简单GETPOST操作。

Can anyone please shed some light on why the missed wrapping caused this change in the expected behavior? 谁能说明为什么错包导致预期行为发生这种变化吗?

Because this: 因为这:

one(two());

calls two , then calls one with two 's return value. 来电 two ,然后调用one带有two的返回值。 But this: 但是这个:

one(function() {
    two();
});

creates a function and calls one with it. 创建一个函数并用它调用one The function will only be run when and if the code in one calls the function. 仅当one代码调用该函数时,该函数才会运行。

one is $.ajax . one$.ajax two is your filter / remove code. two是您的filter / remove代码。

It's because the argument to done is expected to be a function. 这是因为done的参数应该是一个函数。 An actual function object (recall that functions are "first class" in Javascript, meaning that a function can be passed to other functions, or returned from a function, just like any other value) - which will then be executed when the Ajax response is received. 实际的函数对象(请记住,函数是Javascript中的“第一类”,这意味着一个函数可以传递给其他函数,或者像其他任何值一样从函数返回)-然后在Ajax响应为收到。

In addition, like in most languages, function arguments given in the form of more complex expressions need to actually be evaluated before the function is called. 此外,像大多数语言一样,以更复杂的表达式形式给出的函数参数需要在调用函数之前进行实际求值。 It presumably doesn't surprise you at all that when you do: 当您这样做时,大概不会让您感到惊讶:

var a = "hello";
var b = "world;
console.log(a + " " + b);

the JS engine first evaluates the a + " " + b expression to obtain the string "hello world", which is then fed into console.log . JS引擎首先评估a + " " + b表达式以获得字符串” hello world“,然后将其输入console.log

Well, exactly the same thing is going on in your first example: 好吧,在第一个示例中发生了完全相同的事情:

$.ajax({
    url: "RemoveUser",
    type: "POST",
    data: {
        userID: userID
    }
}).done(
    $('.row').filter(function () {
        if ($(this).data()["userID"] === userID) {
            return true;
        }
    }).remove()
);

Here the argument to done has to be evaluated first - which means all of that code with .filter and .remove is executed. 这里的参数done必须首先评估-这意味着所有与该代码的.filter.remove被执行。 And this happens right away when the script is first loaded and ran. 当脚本首次加载并运行时,这种情况立即发生。 (It doesn't result in a function - arguably this should cause an error, but JS is a dynamically-typed language and notoriously relaxed about what it will allow without throwing an early error. I'm not going to get into the debate here as to whether this is a good or bad thing - whether you like it or not, it simply happens.) (它不会产生函数-可以说这会导致错误,但是JS是一种动态类型的语言,并且众所周知它在不引发早期错误的情况下放宽了它的允许范围。我不在这里进行讨论关于这是好事还是坏事-无论您是否喜欢,它都会发生。)

In your second example, with the "wrapper function": 在第二个示例中,使用“包装函数”:

$.ajax({
    url: "RemoveUser",
    type: "POST",
    data: {
        userID: userID
    }
}).done(function () {
    $('.row').filter(function () {
        if ($(this).data()["userID"] === userID) {
            return true;
        }
    }).remove();
});

the difference is that a function value is actually passed in (as the API requires to work properly), and this function is not executed yet . 区别在于,实际上传入了一个函数值(因为API需要正常工作), 而该函数尚未执行 The function argument is a "callback", to be executed when the Ajax is over. 函数参数是“回调”,将在Ajax结束时执行。 The argument still gets "evaluated" in advance, in that the function object is (I presume) created internally, somehow - but the code inside it doesn't get executed. 该参数仍会事先被“评估”,因为(我认为)该函数对象是以某种方式在内部创建的-但其中的代码未执行。 jQuery's $.ajax simply accepts this function argument and executes it ("calls it back") when the time is right. jQuery的$.ajax仅接受此函数参数并在适当的时候执行它(“回调”)。

To add to what TJ mentioned .. this is how callbacks work. 要添加到TJ提到的内容中,这就是回调的工作方式。 Suppose you had written the function function done(argument) . 假设您已经编写了函数function done(argument) Lets say argument is a function which we pass as parameter(callback function). 可以说argument是一个我们作为参数传递的函数(回调函数)。 Now if you want to execute the argument then in your function definition you must include function done(argument){ argument(); } 现在,如果要执行argument则必须在函数定义中包括function done(argument){ argument(); } function done(argument){ argument(); } . function done(argument){ argument(); } In your case the argument is 你的情况的argument

function () {
$('.row').filter(function () {
    if ($(this).data()["userID"] === userID) {
        return true;
    }
}).remove();
}

So if you remove the function wrapper then the body will not execute when intended. 因此,如果删除函数包装器,则主体将在预期的时候不执行。 I hope this makes sense. 我希望这是有道理的。 Please let me know if you have any more doubts on this. 如果您对此有任何疑问,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM