Promise.resolve () внутри обработчика кликов - PullRequest
1 голос
/ 29 мая 2020

Я пытаюсь создать декораторы для некоторых обработчиков событий: несколько простых функций, которые принимают обработчик A в качестве параметра и возвращают функцию B , которая выполняет некоторые действия, а затем call A(...arguments).

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

Это особенно очевидно в случае тега <a href="some/path">bla</a> с асинхронным c обработчик события click, который ожидает, пока следующий поток завершит sh его выполнение (ie в какой-то момент имеет await Promise.resolve() ).

, например, с учетом этого кода

<a href="">click</a>
<script>
    const a = document.querySelector('a')
    a.addEventListener('click', fireLastDecorator(handler))
    a.addEventListener('click', () => console.log('doing stuff...'))

    setTimeout(click, 10000)

    function handler(e) {
        e.preventDefault()
        console.log('done')
    }

    function fireLastDecorator(f) {
        return async function() {
            await Promise.resolve()
            f.apply(this, arguments)
        }
    }

    function click() {
        a.click()
    }
</script>

в течение 10-секундного тайм-аута я могу щелкнуть в любое время по ссылке: страница не перезагружается, потому что оператор e.preventDefault() предотвратит ссылка для загрузки, даже если есть await Promise.resolve().

Но когда setTimeout запускает свою функцию click (программно), страница начинает перезагружаться, как только программа ждет await Promise.resolve(). Функция продолжает свое выполнение после ожидания (вы можете увидеть строку «done», напечатанную на консоли, если у вас активен постоянный журнал), но страница все равно перезагружается.

Интересно, почему это поведение отличается .

Это также заметно при вводе типа submit.

EDIT

В отладчике я заметил, что скрипт следует по другому пути, когда щелчок запускается вручную, а не через js: при запуске вручную обработчик не ожидает разрешения Promise, поэтому второй обработчик запускается после первого (как если бы Promise.resolve () игнорировался). При запуске через js обработчик ожидает обещания, поэтому второй добавленный обработчик запускается перед первым.

1 Ответ

1 голос
/ 29 мая 2020

Разница в том, что в случае setTimeout вы вызываете preventDefault() в обратном вызове async, который содержит обещание await -ed. Когда вы ожидаете Promise, событие завершается, и после этого перехватить его с помощью preventDefault().

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