
18.08.2021, 12:12
|
Новичок на форуме
|
|
Регистрация: 18.08.2021
Сообщений: 4
|
|
async в анонимной функции
Добрый день, возник вопрос, который я не могу решить своими силами. Есть скрипт:
'use strict';
var btn = $('.form_submit');
function AJAX() {
return new Promise(function(resolve, reject){
$.ajax({
type: "POST",
url: "/get_building",
data: $('form').serialize(),
type: 'POST',
success: function(response) {
var json = jQuery.parseJSON(response); //Прочитать ответ сервера
var resp_list = json.resp; //массив с ключем par_buld_resp (из функции get_building main.py)
console.log(`Это resp_list ${resp_list}`);
resolve(resp_list);
},
error: function(error) {
console.log(error);
reject(error);
}
});
})
}
async function checkForm() {
let promise = await AJAX();
var title = $('.add_building_form').val();
console.log(`это промис ${promise}`);
console.log(`это title ${title}`);
return(false);
}
$(document).ready(function(){
btn.click(function(){
let answer = checkForm();
console.log(`Это answer ${answer}`);
if(answer==false) {
return false;
}
else
return false;
//{form.submit();}
})
})
который при клике по кнопке запускает функцию checkForm. Та в свою очередь запускает другую функцию, которая через AJAX обращается к бд и проверяет, есть ли уже запись в БД с таким названием. checkForm принимает промис от функции AJAX в котором либо old (то есть запись уже есть), либо new - если записи нет, а так же проверяет введенную строку (пока не реализовал) и возвращает промис (пока только false). В функциях расставлены логи, вот вывод:
Это answer [object Promise]
Это resp_list Old
это промис Old
это title 123
Из всего этого становится понятно, что основная анонимная функция, которая ждет нажатия на кнопку не ждет пока checkForm выполнится. Вопрос: как сделать анонимную функцию асинхронной?
если я делаю так:
btn.click(async function(){
let answer = await checkForm();
....
выскакивает ошибка интерпретатора uncaught exception: Object
|
|

18.08.2021, 12:25
|
 |
Тлен
|
|
Регистрация: 02.01.2010
Сообщений: 6,593
|
|
Должно работать, ошибка где-то в другом месте.
Разве что return false не сработает, потому что async функция возвращает не значение, а Promise отдающий значение. Соответственно, форма попытается отправиться.
Чтобы остановить действие click - ты должен его остановить прямо сейчас, асинхронная же функция выполнится когда-нибудь потом.
Решение: останавливать событие в любом случае, а уже потом, когда отработает асинхронная функция - триггерить нужное действе вручную.
__________________
29375, 35
Последний раз редактировалось Aetae, 18.08.2021 в 12:32.
|
|

18.08.2021, 12:52
|
 |
Профессор
|
|
Регистрация: 08.11.2017
Сообщений: 641
|
|
<input type="button" class="form_submit" value="click" />
<script>
document.querySelector('.form_submit').addEventListener('click', async function() {
const result = await Promise.resolve('ok');
console.log(result);
});
</script>
|
|

18.08.2021, 16:04
|
 |
Профессор
|
|
Регистрация: 03.02.2020
Сообщений: 2,763
|
|
let promise = await AJAX();
Функция AJAX возвращает promise. Но await AJAX() вернет только результат успешного разрешения промиса, т.е. resp_list. error в случае неудачи она не вернет.
let answer = checkForm();
checkForm описана как async. Она возвращает промис, который разрешается, как false.
Что бы получить этот самый false, ее надо вызывать
let answer = await checkForm();
выскакивает ошибка интерпретатора uncaught exception: Object
Возможно потому, что в ajax срабатывает error, но он не ловится await.
Попробуйте вызывать так
try {
let promise = await AJAX();
var title = $('.add_building_form').val();
console.log(`это промис ${promise}`);
console.log(`это title ${title}`);
} catch (error) {
console.log('Error', error)
}
return(false);
|
|

19.08.2021, 13:57
|
Новичок на форуме
|
|
Регистрация: 18.08.2021
Сообщений: 4
|
|
Немного переделал код, получилось вот так:
'use strict';
var btn = document.querySelector('.form_submit');
function AJAX() {
return new Promise(function(resolve, reject){
$.ajax({
type: "POST",
url: "/get_building",
data: $('form').serialize(),
type: 'POST',
success: function(response) {
console.log(`Это response ${response}`);
var json = jQuery.parseJSON(response); //Прочитать ответ сервера
var resp_list = json.resp; //массив с ключем par_buld_resp (из функции get_building main.py)
console.log(`Это resp_list ${resp_list}`);
resolve(resp_list);
},
error: function(error) {
console.log(`Это error в AJAX ${error.name}`);
reject(error);
}
});
})
}
async function checkForm() {
var title = $('.add_building_form').val();
if (title == '') {
return "No"
}
try {
let promise = await AJAX();
console.log(`это промис ${promise}`);
console.log(`это title ${title}`);
if (promise == 'Old') {
return "No"
}
else return "Yes";
} catch (error) {
console.log(`Error ${error}`);
}
return("No");
}
btn.addEventListener('click', async function() {
const answer = await checkForm();
console.log(`Это answer ${answer}`);
if (answer == "No") {
return false;
}
else {
return btn.submit();
}
});
При вводе пустой строки, как и полагается запрос ловится еще в функции checkForm с выводом в консоль:
Это answer No
При вводе каких либо значений, затык происходит в функции AJAX со следующим логом:
Это error в AJAX undefined
Error [object Object]
Это answer No
причем на сервере (Flask) обращения не приходит.
Если использовать старый код:
$(document).ready(function(){
var btn = $('.form_submit');
btn.click(function(){
var answer = AJAX();
var title = $('.add_building_form').val();
if(title==''){
return false;
}
else
return false;
//{form.submit();}
})
})
function AJAX() {
$.ajax({
type: "POST",
url: "/get_building",
data: $('form').serialize(),
type: 'POST',
success: function(response) {
var json = jQuery.parseJSON(response); //Прочитать ответ сервера
var resp_list = json.resp; //массив с ключем par_buld_resp (из функции get_building main.py)
console.log(resp_list);
return resp_list;
},
error: function(error) {
console.log(error);
return error;
}
});
}
ответ приходит, AJAX отрабатывает, resp_list в зависимости от того, что ввел получает значение New или Old. Но так как асинхронность не прописана, анонимная функция, вызывающая AJAX() получает undefined (оно понятно, так как анонимная выполняется дальше а значение в ответе еще не определено).
Не могу понять, чем первый AJAX отличается от второго, затык именно в этой функции, но найти его я не могу (
|
|

19.08.2021, 16:41
|
 |
Тлен
|
|
Регистрация: 02.01.2010
Сообщений: 6,593
|
|
Цитата:
|
ввел получает значение New или Old
|
Нет.
Если succes - возвращает (в никуда) значение New.
Если error - ничего не делает.
В новом варианте:
Если succes - возвращает New.
Если error - кидает ошибку.
Чтоб не кидало ошибку - не надо кидать ошибку. На error верни вместо этого руками resolve('No'); вместо reject(error);.
Если при ошибке сервера таки должна быть ошибка, а не No, то поправь сервер, чтоб при возврате No он не ставил в код ответа ошибку.
__________________
29375, 35
|
|

22.08.2021, 15:41
|
Новичок на форуме
|
|
Регистрация: 18.08.2021
Сообщений: 4
|
|
Решил сделать так:
'use strict';
const requestURL = '/get_building';
let frm = document.forms[0];
frm.onsubmit = async function(event) {
let body = 'building_name=' + frm.building_name.value; //получаем 'building_name=123', Если ввели в форму 123
let answer = AJAX("POST", requestURL, body)
event.preventDefault();
answer.then(data => {
if(data.resp=='New'){
console.log('Новое здание');
}
else {
console.log('Старое здание');
}
})
.catch(err => console.log(err))
}
function AJAX(method, url, body = null) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open(method, url);
xhr.responseType = 'json';
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhr.onload = () => {
if (xhr.status >= 400) {
reject(xhr.response)
} else {
resolve(xhr.response)
}
}
xhr.onerror = () => {
reject(xhr.response)
}
xhr.send(body)
})
}
Запрос отправляется и приходит ответ. Мы его выводим в консоль. То, что было введено в форму сравнивается с тем, что есть в БД.
Не могу сделать так, что бы если запись уже есть и срабатывает условие
if(data.resp=='New'){
console.log('Новое здание');
}
запрос отправлялся. Сейчас он блокируется вот этим:
event.preventDefault();
Если сделать вот так:
const requestURL = '/get_building';
let frm = document.forms[0];
frm.onsubmit = async function(event) {
let body = 'building_name=' + frm.building_name.value; //получаем 'building_name=123', Если ввели в форму 123
let answer = AJAX("POST", requestURL, body)
answer.then(data => {
if(data.resp=='New'){
console.log('Новое здание');
}
else {
return event.preventDefault();
console.log('Старое здание');
}
})
.catch(err => console.log(err))
}
то запрос все равно отправляется. Почему так происходит, и как надо?
|
|

22.08.2021, 22:25
|
 |
Профессор
|
|
Регистрация: 03.02.2020
Сообщений: 2,763
|
|
Сообщение от zloy_ej
|
то запрос все равно отправляется. Почему так происходит, и как надо?
|
Потому, что выход из frm.onsubmit происходит раньше, чем закончится
AJAX("POST", requestURL, body) и запрос уже будет отпроавлен. А event.preventDefault() будет выполняться уже потом
Не знаю вашего html кода, но сделать можно так - вместо кнопки <input type=submit> использовать <button type=button> и вместо frm.onsubmit
const requestURL = '/get_building';
let frm = document.forms[0];
let but = ...// наша кнопка
but.onclick = async function(event) {
let body = 'building_name=' + frm.building_name.value; //получаем 'building_name=123', Если ввели в форму 123
let answer = AJAX("POST", requestURL, body)
answer.then(data => {
if(data.resp=='New'){
console.log('Новое здание');
frm.submit()
}
else {
console.log('Старое здание');
}
})
.catch(err => console.log(err))
}
|
|

23.08.2021, 12:43
|
Новичок на форуме
|
|
Регистрация: 18.08.2021
Сообщений: 4
|
|
Большое спасибо всем принимавшим участие в обсуждении сабжа. Задача решена. Дальше буду навешивать функционал и облагораживать код, но это уже другая история! ) Выкладываю то, что получилось, возможно кому нибудь пригодится.
Html:
{% extends 'base.html' %}
{% block content %}
<p><h3 class="helper">Добавляются здания, сооружения или территория предприятия</h3></p>
{% for cat, msg in get_flashed_messages(True) %}
<div class="flash {{cat}}">{{msg}}</div>
{% endfor %}
<form action="/add_building" method="post" class="form_add">
<p><label>Название: </label> <input type="text" name="building_name" value="" class='add_building_form' placeholder="Введите название здания" required></p>
<p><button type="button" value="Добавить" class="form_submit">Отправить</button></p>
</form>
<!--<script src="{{url_for('static', filename='js/add_building.js') }}"></script>-->
<script src="{{url_for('static', filename='js/proba.js') }}"></script>
<!--<script src="{{url_for('static', filename='js/execise.js') }}"></script>-->
<!--<script src="{{url_for('static', filename='js/ex1.js') }}"></script>-->
{% endblock %}
бэк построен на фласке, там тоже не все гладко, но там наведу порядок со временем, вот участок с обработчиком:
Код:
|
@app.route('/get_building', methods=['GET', 'POST'])
def get_building():
print(request.form)
build_name = request.form['building_name']
db = get_db()
mydbase = Building(db)
building_id = mydbase.getBuilding(build_name, ALL=False)
print('new_building', build_name)
print('building_id', building_id)
if (building_id):
print('Уже есть')
return json.dumps({'resp': "Old"})
else:
print('Новое здание')
return json.dumps({'resp': "New"}) |
Далее собственно JS:
'use strict';
const requestURL = '/get_building';
let frm = document.forms[0];
let but = frm.elements[1];
but.onclick = async function(event) {
let body = 'building_name=' + frm.building_name.value; //получаем 'building_name=123', Если ввели в форму 123
let answer = AJAX("POST", requestURL, body)
answer.then(data => {
if(data.resp=='New'){
console.log('Новое здание');
frm.submit();
}
else {
console.log('Старое здание');
}
})
.catch(err => console.log(err))
}
function AJAX(method, url, body = null) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open(method, url);
xhr.responseType = 'json';
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhr.onload = () => {
if (xhr.status >= 400) {
reject(xhr.response)
} else {
resolve(xhr.response)
}
}
xhr.onerror = () => {
reject(xhr.response)
}
xhr.send(body)
})
}
Знаю что кривенько написано, но в конце концов я только учусь!)
|
|
|
|