Как обработчики событий jQuery ставятся в очередь и выполняются? - PullRequest
18 голосов
/ 04 апреля 2019

У меня есть форма ввода с кнопкой отправки. Я не хочу, чтобы пользователь мог дважды щелкнуть кнопку отправки и дважды отправить форму ...

Итак, я добавил следующий jQuery в мою форму:

var prevSubmitTime = new Date('2000-01-01');

function preventFromBeingDoubleSubmitted() {
    $('form').each(function () {
        $(this).submit(function (e) {
            if ($("form").valid()) {
                var curSubmitTime = new Date($.now());

                // prevent the second submit if it is within 2 seconds of the first submit
                if (curSubmitTime - prevSubmitTime < 2000) {
                    e.preventDefault();
                }
                prevSubmitTime = new Date($.now());
            }
        });
    });
}

$(document).ready(function () {
    preventFromBeingDoubleSubmitted();
});

Приведенный выше код хранит время отправки и предотвращает повторную отправку. Если это слишком рано (менее 2 секунд), я не хочу постоянно отключать кнопку отправки, если возникает ошибка на стороне сервера. .

Этот код выполняет то, что я хочу, но при отладке кода я никогда не смогу достичь точки останова на e.preventDefault(); ... даже если я дважды нажму кнопку отправки.

Похоже, что второе событие отправки ожидает завершения первого события отправки перед запуском.

Но, если я уберу функцию preventFromBeingDoubleSubmitted(), я смогу дважды отправить форму, дважды щелкнув по кнопке отправки.

Может кто-нибудь объяснить, почему иногда события отправки запускаются сразу один за другим ... а иногда это не так? Помещает ли обработчик событий внутри .each(), как они влияют на поведение при выполнении?

Ответы [ 5 ]

4 голосов
/ 06 апреля 2019

Формы при отправке по умолчанию переходят на набор action url.В случае, если он не установлен явно, URL является текущей страницей.Первый запрос на отправку в конечном итоге запускает процесс навигации.При этом загруженный в данный момент код JavaScript выгружается.Это включает в себя обработчики событий.Следовательно, почему вы получаете несоответствие возможности двойной подачи или нет.Если сетевой запрос и другие страницы обрабатываются, URL-адрес действия происходит быстрее, чем скорость, необходимая для повторного нажатия на обработчики событий, и ваша точка останова больше не будет вызываться / достигаться, поскольку они уже выгружены.И наоборот, если сетевой запрос медленнее, вы сможете вызвать обработчик и вызвать точку останова (если она еще не выгружена).

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

Теперь, если ваша настоящая форма не выполняет обычную отправку формы, и вы используете что-то вроде запроса ajax, соединения через веб-сокет и т. Д., Тогда выустановит кнопку в положение «отключено» (или установит флаг занятости) перед запросом и сбросит ее в обратном вызове запроса ajax, событии веб-сокета и т. д.

Например:

jQuery('form').on('submit',function(e){
  e.preventDefault();
  var fd = new FormData(this);
  jQuery('yourbutton').prop('disabled',true);
  fetch('url',{method:"post",body:fd}).then(()=>jQuery('yourbutton').prop('disabled',false));
});
4 голосов
/ 04 апреля 2019

В вашем фрагменте я добавил несколько журналов, которые могут быть полезны.Поскольку вы задаете более одного вопроса, я отвечу один за другим.

var prevSubmitTime = new Date('2000-01-01');

function preventFromBeingDoubleSubmitted() {
    $('form').each(function () {
        $(this).submit(function (e) {
            console.log('I am going to submit form');
            if ($("form").valid()) {
                var curSubmitTime = new Date($.now());
		console.log('I am a valid form')
                // prevent the second submit if it is within 2 seconds of the first submit
                if (curSubmitTime - prevSubmitTime < 2000) {
                    console.log('A small time difference. So I am stopping')
                    e.preventDefault();
                }
                prevSubmitTime = new Date($.now());
            }
        });
    });
}

$(document).ready(function () {
    preventFromBeingDoubleSubmitted();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.0/jquery.validate.js"></script>

<form id="myform">
    <input type="text" name="q" required="required" />
    <br />
    <input type="text" name="bar" required="required" />
    <br />
    <br />
    <input type="submit" />
</form>

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

Думаю, вы сами ответили на этот вопрос.Вы добавляете код, чтобы проверить, есть ли разница между временем нажатия кнопки «Отправить» в первый раз и вторым.Если разница во времени существует, то вы прекращаете отправку второй формы.

Я никогда не смогу достичь точки останова на e.preventDefault ();

Причина, по которой вы 'Вы не можете получить консоль, вы перенаправляетесь с этой страницы, когда нажимаете кнопку «Отправить».Итак, консоль очищена.Если вы хотите увидеть консоль, используйте функцию ajax для отправки формы.А по возвращении вы, вероятно, можете куда-то перенаправить страницу.

Влияет ли размещение обработчика событий внутри .each (), на поведение их выполнения?

Нет.Это просто итератор.Это не повлияет на функцию отправки.

Я добавил ссылку на jsfiddle.Добавление оповещения перед protectDefault на мгновение остановит перенаправление страницы.Это докажет, что казнь произошла.

http://jsfiddle.net/2vugwyfe/

1 голос
/ 06 апреля 2019

Если вы добавите e.preventDefault(); непосредственно перед выполнением $("form").valid(), вы увидите, что выдается ошибка.

script.js:7 Uncaught TypeError: $(...).valid is not a function
at HTMLFormElement.<anonymous> (script.js:7)
at HTMLFormElement.dispatch (jquery.min.js:2)
at HTMLFormElement.y.handle (jquery.min.js:2)

Эта ошибка сначала не была видна, потому что отправка фактически изменяет страницу (обновляет страницу в этом случае), если ничего не реализовано.

Однако в целом практика заключается в переходе на другую страницу после отправки формы. Если вы все еще хотите придерживаться своего подхода и ограничить количество отправляемых, я предлагаю сохранить состояние submit в локальной переменной и изменить его в соответствии с проверкой на стороне сервера.

И последнее. Я не понимаю итерации в формах, так как в вашем HTML есть только одна -> $('form').each бесполезна.

1 голос
/ 05 апреля 2019

Ваше решение слишком сложное. Самый простой способ предотвратить двойную отправку - отключить кнопку отправки при отправке.

Пример:

var submittable = false;
$('form').submit(function (e) {
  if (!submittable) {
    e.preventDefault();
    var $this = $(this);
    var $submitButton = $this.find('button[type="submit"]');
    $submitButton.attr('disabled', true);

    if (CONDITION_SATISFIED) {
      submittable = true;
      $this.submit()
    } else {
      $submitButton.attr('disabled', false);
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<button type="submit">Submit</button>
</form>
0 голосов
/ 06 апреля 2019

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

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="myform">
    <input type="text" name="myInput" />
    <div id="submit" onclick="myform_submit()" />
</form>

и:

function myform_submit() {
    if ($('#submit').hasClass('busy')) { return; }
    $('#submit').addClass('busy');

    // do the tasks then remove the `busy` class :
    $('#submit').removeClass('busy');
}

Я просто показываю идею, вы можете сделатьлучше.

...