Как из JavaScript ПОСЛЕДОВАТЕЛЬНО вызвать два серверных REST - метода?
У меня возникает такая проблема.
Есть одностраничное приложение, которое работает с сервером, дёргая по REST разные серверные методы. В какой то момент мне понадобилось по событию (например, нажатию кнопки на странице) вызвать два метода, но последовательно:
данные, которые вернет первый метод, нужно передать во второй.
Вызов REST я делаю через axios, и вызов выглядит так:
axios.post('/api/method1/', $.param(state1))
.then((response) => {
console.log('on /api/method1/ response:' + JSON.stringify(response));
... // код использующий данные method1
})
.catch((error) => {
console.log(error);
alert('Error in request: /api/method1/');
});
Вызов другого серверного метода такой же, с точностью до названия метода.
Если я просто напишу последоваетльно два вызова в JS, то клиент быстренько вызовет первый серверный метод, не дожидаясь ответа - вызовет второй серверный метод, и будет спокойно ждать, кто первый ответит.
А мне надо чтобы был вызов первого метода, постоять, подождать, пока ответит сервер, выполнить еще кусочек кода, который использует эти данные, а потом вызвать второй серверный метод.
Я не могу объединить два метода на сервере, потому что те данные, которые передаются во второй метод, могут быть изменены на клиентской стороне. Так что решение "объединить на сервере два вызова в один" не подходит.
Единственное, что приходит в голову - это "написать второй вызов внутри первого":
axios.post('/api/method1/', $.param(state1))
.then((response) => {
console.log('on /api/method1/ response:' + JSON.stringify(response));
... // код использующий данные method1
axios.post('/api/method2/', $.param(state2))
.then((response) => {
console.log('on /api/method2/ response:' + JSON.stringify(response));
... // код использующий данные method2
})
.catch((error) => {
console.log(error);
alert('Error in request: /api/method2/');
});
})
.catch((error) => {
console.log(error);
alert('Error in request: /api/method1/');
});
Но этот вариант мне не нравится - потому, что на практике это приведет к очень большому дублированию кода: сейчас у меня каждый вызов серверного метода в JS оформлен как отдельная функция, и я могу их вызвать последовательно, просто написав один вызов после другого.
Причем, в некотрых случаях мне надо вызывать method2 после method1, а иногда - method3 после method1.
В случае же, если я начинаю в JS - коде объединять вызовы - мне придётся предусмотреть все возможные сочетания "парных" вызовов.
Ну должен же быть способ сделать из асинхронного кода обратно синхронный?
Спасибо заранее.
Ответы (2 шт):
Почему вы создаете call back hell когда манипулируете Promise
axios.post('/api/method1/', $.param(state1))
.then((response) => {
console.log('on /api/method1/ response:' +
JSON.stringify(response));
... // код использующий данные method1
return axios.post('/api/method2/', $.param(state2));
})
.then((responce2) => {
console.log('on /api/method2/ response:' +
JSON.stringify(response2));
... // код использующий данные method2
})
.catch((error) => {
console.log(error);
});
Пожоже, ответ оказался довольно прост.
Видимо, это единственный путь, и он заключается в том, чтобы во всём коде перейти на async-await.
Для меня было неожиданностью, что при этом ВСЕ функции должны быть помечены как async, иначе это вызывает ошибку 'Uncaught SyntaxError: await is only valid in async function'
Тогда мой код для двух последовательных вызовов стал выглядеть приблизительно так:
async function GetDataFromServer1(arg1){
var tmp_json = { "arg1" : arg1 };
var tmp = {};
tmp.text = JSON.stringify(tmp_json);
var response = await axios.post('/api/method1/', $.param(tmp));
return response;
}
async function GetDataFromServer2(arg2){
var tmp_json = { "arg2" : arg2 };
var tmp = {};
tmp.text = JSON.stringify(tmp_json);
var response = await axios.post('/api/method2/', $.param(tmp));
return response;
}
async function on_load {
var response1 = await GetDataFromServer1(1);
// ... - здесь может быть произвольный код, формирующий arg2
var response2 = await GetDataFromServer2(arg2);
}
(Причем, видите, значительную часть этого кода - по три строки в каждой из двух процедур - занимает подготовка данных в нужном для передачи формате. Иначе - код можно было бы сделать еще короче)
Спасибо всем, кто обратил внимание на вопрос и помог советами!