Ajax операция выполняется позже, чем javascript функция - PullRequest
0 голосов
/ 29 мая 2020

Я создаю проект django, который представляет собой веб-сайт, отправляющий форму на сервер, и сервер отвечает набором запросов, только что зарегистрированным в форме, и строкой сообщения «Создать новое событие успешно».

Это код для этого:
listevent - это еще одна функция javascript, которая показывает только что полученный сервером набор запросов в div "боковой панели". После этого, набрав document.getElementById("sidebar").insertAdjacentHTML( 'afterbegin', "Create new event successful." );, над результатом добавляется сообщение.

Javascript

function makeEvent(event){
            event.preventDefault();
            var year = event.target.childNodes[3].children[0].value.slice(0,4);
            var month = event.target.childNodes[3].children[0].value.slice(5,7);
            var day = event.target.childNodes[3].children[0].value.slice(8,10);
            var form = $("#makeEventForm");
            $.ajax({
                type: form.attr('method'),
                url: form.attr('action'),
                data: form.serialize(),
                success: function(response){
                    console.log(response);                   
                    listevent(year, month, day);
                    document.getElementById("sidebar").insertAdjacentHTML( 'afterbegin', "Create new event successful." );
                },
                error: function(request,status,error){
                    if (request.status == 599) {
                        listevent(year, month, day);
                        document.getElementById("sidebar").insertAdjacentHTML( 'afterbegin', "Error : time overlaps with another event" );
                    } else {
                        alert("code:"+request.status+"\n"+"message:"+status+"\n"+"error:"+error);
                    }
                },
            });
        }

Проблема в том, что когда эта функция makeEvent выполнялась и ajax операция успешно выполнена, вторая строка функции успеха (listevent(year, month, day);), похоже, выполняется позже третьей строки. В результате сообщение «Создать новое событие успешно» не отображается, потому что функция listevent перезаписывает все содержимое в sidebar div.

Итак, я попытался использовать setTimeout в третьей строке, но похоже, что не работает все время. Это сработает, если я установлю достаточно большое значение времени, но это выглядит так плохо.

Итак, мой вопрос:
1. Вторая строка функции успеха выглядит так, как будто она выполняется позже третьей строки, это это верно?
2. Если да, чтобы запустить третью строку после завершения второй строки, что мне делать?


Изменить

функция списка событий

function listevent(year, month, day){
            $.ajax({
                type: "POST",
                url: "{% url 'listevent' %}",
                data: {'year':year, 'month':month, 'day':day, 'csrfmiddlewaretoken': '{{ csrf_token }}'},
                dataType: "json",
                success: function(response){
                    $("#sidebar").attr('year', year);
                    $("#sidebar").attr('month', month);
                    $("#sidebar").attr('day', day);
                    events = JSON.parse(response.events)
                    var str = "<h4>"+year+"/"+month+"/"+day+"</h4><br>"
                    if(events.length > 0){
                         events.forEach(event => str += (event['fields']['start_time']+" - "+event['fields']['title']+"<br>"));
                    } else {
                        str += "No events currently."
                    }
                    $("#sidebar").html(str);
                    var btn = $("<button></button>").html("New event");
                    btn.click(function(){
                        makeEventClick(day);
                    });
                    $("#sidebar").append(btn);
                },
                error: function(request,status,error){
                       console.log(error);
                },
            });
        }

Ответы [ 2 ]

0 голосов
/ 29 мая 2020

Это очевидно, потому что внутри listevent() вы вызываете Asyn c AJAX, поэтому он будет работать параллельно и, очевидно, будет работать позже, чем ответ сценария, поэтому сначала будет выполнен сценарий, а затем ajax ответ придет и вступит в силу.

Для исправления вы можете использовать async:false - метод ajax. Это заставит скрипт ждать, пока ajax не вернет ответ. Но это не очень хорошая практика.

function listevent(year, month, day){
        $.ajax({
            type: "POST",
            url: "{% url 'listevent' %}",
            async:false, // added
            data: {'year':year, 'month':month, 'day':day, 'csrfmiddlewaretoken': '{{ csrf_token }}'},
            dataType: "json",
            success: function(response){
                $("#sidebar").attr('year', year);
                $("#sidebar").attr('month', month);
                $("#sidebar").attr('day', day);
                events = JSON.parse(response.events)
                var str = "<h4>"+year+"/"+month+"/"+day+"</h4><br>"
                if(events.length > 0){
                     events.forEach(event => str += (event['fields']['start_time']+" - "+event['fields']['title']+"<br>"));
                } else {
                    str += "No events currently."
                }
                $("#sidebar").html(str);
                var btn = $("<button></button>").html("New event");
                btn.click(function(){
                    makeEventClick(day);
                });
                $("#sidebar").append(btn);
            },
            error: function(request,status,error){
                   console.log(error);
            },
        });
    }

Поэтому в качестве хорошей практики вы можете переместить следующую строку внутри listevent().

function listevent(year, month, day){
        $.ajax({
            type: "POST",
            url: "{% url 'listevent' %}",
            data: {'year':year, 'month':month, 'day':day, 'csrfmiddlewaretoken': '{{ csrf_token }}'},
            dataType: "json",
            success: function(response){
                $("#sidebar").attr('year', year);
                $("#sidebar").attr('month', month);
                $("#sidebar").attr('day', day);
                events = JSON.parse(response.events)
                var str = "<h4>"+year+"/"+month+"/"+day+"</h4><br>"
                if(events.length > 0){
                     events.forEach(event => str += (event['fields']['start_time']+" - "+event['fields']['title']+"<br>"));
                } else {
                    str += "No events currently."
                }
                $("#sidebar").html(str);
                var btn = $("<button></button>").html("New event");
                btn.click(function(){
                    makeEventClick(day);
                });
                $("#sidebar").append(btn);
                document.getElementById("sidebar").insertAdjacentHTML( 'afterbegin', "Create new event successful." ); // Added
            },
            error: function(request,status,error){
                   console.log(error);
            },
        });
    }
0 голосов
/ 29 мая 2020

Похоже, что AJAX работает асинхронно. listevent успешно запущен, но, поскольку его операция AJAX, код не будет ждать, пока будет получен ответ, оставшийся от обратных вызовов успеха / неудачи.

Итак, вызывается listevent и * Вызов 1012 * запущен, и вместо того, чтобы ждать его завершения, он переходит к следующей строке document.getElementById("sidebar").insertAdjacentHTML( 'afterbegin', "Create new event successful." );

Итак, я предлагаю переместить этот nside listevent в конце успешного обратного вызова.

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