Ajax сделал обратный вызов, не ожидая, когда это не функция - PullRequest
1 голос
/ 21 марта 2019

Пролог:

Хотя я имел дело с стандартом [1] Ajax требует пару месяцев, простая ошибка в моем коде заставила меня понять сегодня, что есть еще много чего, что я до сих пор не понял, что Я чувствую, что мне нужно кое-что прояснить.

Факт:

Я пишу интерфейс администрирования для добавления и удаления пользователей из веб-приложения, написанного на MVC 5. У меня был этот код, вызывающий метод действия (в конце концов выполняющий хранимую процедуру в базе данных 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 или базовые данные.

Ответы [ 3 ]

4 голосов
/ 21 марта 2019

Может ли кто-нибудь пролить свет на то, почему пропущенная упаковка привела к такому изменению ожидаемого поведения?

Потому что это:

one(two());

звонки two, затем вызывает one с возвращаемым значением two.Но это:

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

создает функцию и вызывает one с ней.Функция будет запускаться только в том случае, если и код из one вызывает функцию.

one равен $.ajax.two - это ваш filter / remove код.

2 голосов
/ 21 марта 2019

Это потому, что аргумент 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. Аргумент по-прежнему «оценивается» заранее, так как объект функции (я полагаю) создается как-то внутренне, но код внутри него не выполняется. $.ajax в jQuery просто принимает этот аргумент функции и выполняет его («перезванивает»), когда настало время.

0 голосов
/ 21 марта 2019

Чтобы добавить к тому, что упомянул TJ ... вот как работают обратные вызовы. Предположим, вы написали функцию function done(argument). Допустим, argument - это функция, которую мы передаем в качестве параметра (функция обратного вызова). Теперь, если вы хотите выполнить argument, тогда в вашем определении функции вы должны включить function done(argument){ argument(); }. В вашем случае argument это

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

Таким образом, если вы удалите обертку функции, тело не будет выполнено, как предполагалось. Я надеюсь это имеет смысл. Пожалуйста, дайте мне знать, если у вас есть какие-либо сомнения по этому поводу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...