Асинхронная обработка форм
Занимаюсь давно обещанным обновлением текстового редактора на портале. С наскока сделать не получилось - постоянно натыкаюсь на технический долг, который так или иначе мешает подключению к сайту новых библиотек. Интересно, что большинство современных WYSIWYG-редакторов Markdown делаются под популярные фреймворки: React, Angular, Vue. Найти что-то стабильной под сайт, написанный на ванильном JS, не так то просто.
Пока закрываю техдолги, добавил на сайт функцию для асинхронной обработки форм. А ванильные HTML-формы на Авторском Комиксе используются много где. В чем суть проблемы: обработчик отправки формы (событие submit) синхронный, как и все другие обработчики в JS. Поэтому, если в момент отправки формы нам нужно в асинхронном режиме дозапросить какие-то данные, просто через await мы это сделать не можем, так как обработчик завершит свою работу раньше, чем дождется выполнения асинхронной функции.
Решение проблемы можно посмотреть в файле AsyncForm.js: предполагается, что все поля формы, которые требуют асинхронных действий перед отправкой формы имеют атрибут 'data-async-processing' и в поле с именем 'processAsync' содержат асинхронные функции, выполняющие необходимые операции. Если у формы есть такие поля, то в момент ее отправки, мы прервем обработку событий, выполним 'processAsync' где это необходимо, и только потом заново сэмулируем отправку формы. При этом эмуляция отправки формы происходит через HTMLFormElement.prototype.requestSubmit.call(form, evt.submitter); что гарантирует, что при наличии нескольких кнопок отправки формы будет сохранена именно та, которую нажал пользователь.
Если у вас есть более элегантное решение для асинхронной обработки событий в JS, в частности событий отправки формы, напишите об этом в комментариях.
авторский комикс
acomics
разработка
редактор
формы
javascript
Сцинк
Хм, любопытно. А что за асинхронные операции выполняют эти поля? Нельзя ли их как-то, хм-м-м, "засинхронить"? Например, с помощью тех же async/await можно сделать так, что вроде бы асинхронная функция будет выполняться синхронно, и в синхронном контексте.
May 02 17:35
Александр Козлов
Сцинк, привет! По поводу async/await - это распространенное заблуждение, они не делают код синхронным, просто скрывают работу с промисами под синтаксическим сахаром. По сути код остается асинхронным:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
Если ты хочешь использовать await внутри обработчика событий, то его придется делать асинхронным (async). А это значит, что обработчик будет возвращать объект Promise, не дожидаясь своего окончания.
Про синхронные операции, которые нужно выполнять при отправке формы, например, запрос рекапчи:
https://cloud.google.com/php/docs/reference/cloud-recaptcha-enterprise/latest/V1.Client.RecaptchaEnterpriseServiceClient#_Google_Cloud_RecaptchaEnterprise_V1_Client_RecaptchaEnterpriseServiceClient__createAssessment__
May 03 14:20 (changed)
Сцинк Replying to Александр Козлов
Александр Козлов, да, проверил - и действительно, вызов функции async в обычной синхронной её не притормаживает.Ну тогда у меня нет идей лучше, чем описанная в посте. Да и вообще, по мне так там вполне годная идея описана, ты можешь добавлять асинхронные процессы для каждого поля отдельно, а хэндлить это будет одно централизованное место, и пространство для факапа вроде бы невелико. Может и не дохрена элегантно, но для костыля в целях совместимости - достаточно хорошее решение.
May 04 01:44