Используя выборку внутри другой выборки в JavaScript
Я хочу получить API и после этого позвонить другому. Разумно ли использовать такой код в javascript?
fetch(url, {
method: 'get',
}).then(function(response) {
response.json().then(function(data) {
fetch(anotherUrl).then(function(response) {
return response.json();
}).catch(function() {
console.log("Booo");
});
});
})
.catch(function(error) {
console.log('Request failed', error)
});
8 ответов
Fetch возвращает обещание, и вы можете связать несколько обещаний и использовать результат 1-го запроса во 2-м запросе:
В этом примере используется API SpaceX для получения информации о последнем запуске, поиска идентификатора ракеты и получения информации о ракете.
var url = 'https://api.spacexdata.com/v2/launches/latest';
var result = fetch(url, {
method: 'get',
}).then(function(response) {
return response.json(); // pass the data as promise to next then block
}).then(function(data) {
var rocketId = data.rocket.rocket_id;
console.log(rocketId, '\n');
return fetch('https://api.spacexdata.com/v2/rockets/' + rocketId); // make a 2nd request and return a promise
})
.then(function(response) {
return response.json();
})
.catch(function(error) {
console.log('Request failed', error)
})
// I'm using the result variable to show that you can continue to extend the chain from the returned promise
result.then(function(r) {
console.log(r); // 2nd request result
});
.as-console-wrapper { max-height: 100% !important; top: 0; }
Нет проблем с вложенностью fetch()
звонки. Это зависит от того, чего вы пытаетесь достичь, вкладывая вызовы.
Вы можете альтернативно использовать .then()
цепочка звонков. Смотрите также Как структурировать вложенные Обещания
fetch(url)
.then(function(response) {
return response.json()
})
.then(function(data) {
// do stuff with `data`, call second `fetch`
return fetch(data.anotherUrl)
})
.then(function(response) {
return response.json();
})
.then(function(data) {
// do stuff with `data`
})
.catch(function(error) {
console.log('Requestfailed', error)
});
Это распространенный вопрос, с которым люди сталкиваются, когда начинают с Promises, включая меня, когда я начинал. Однако сначала...
Здорово, что вы пытаетесь использовать новый API Fetch, но на вашем месте я бы сейчас использовал реализацию XMLHttpRequest, например, jQuery AJAX или переопределенную реализацию Backbone для jQuery. .ajax()
, если вы уже используете эти библиотеки. Причина в том, что API Fetch все еще настолько нов, и поэтому на данном этапе является экспериментальным.
С учетом сказанного, люди определенно используют его, но я не буду в своем собственном рабочем коде, пока он не выйдет из "экспериментального" статуса.
Если вы решили продолжить использовать fetch
есть полифилл в наличии. ПРИМЕЧАНИЕ: вам нужно перепрыгнуть через дополнительные обручи, чтобы правильно работать с ошибками и получать куки с сервера. Если вы уже загружаете jQuery или используете Backbone, просто придерживайтесь их сейчас; во всяком случае, не совсем ужасно.
Теперь на код:
Вам нужна плоская структура, иначе вы упускаете суть Обещаний. Необязательно вкладывать обещания обязательно, потому что обещания решают то, что не могли вложенные асинхронные обратные вызовы (ад обратного вызова).
Вы сэкономите свое время и энергию, а также создаете меньше кода с ошибками, просто используя более читаемую структуру кода. Это не все, но это, так сказать, часть игры.
Обещания состоят в том, чтобы асинхронный код сохранил большинство утраченных свойств синхронного кода, таких как плоский отступ и один канал исключения.
- Петка Антонов (Библиотека Обещания Синей Птицы)
// run async #1
asyncGetFn()
// first 'then' - execute more async code as an arg, or just accept results
// and do some other ops
.then(response => {
// ...operate on response data...or pass data onto next promise, if needed
})
// run async #2
.then(asyncGetAnotherFn)
.then(response => {
// ...operate on response data...or pass data onto next promise, if needed
})
// flat promise chain, followed by 'catch'
// this is sexy error handling for every 'then' above
.catch(err => {
console.error('Request failed', err)
// ...raise exeption...
// ... or, retry promise...
})
Я не видел ответа с синтаксическим сахаром async / await, поэтому отправляю свой ответ.
Другой способ получить "внутри" другой выборки в javascript выглядит так:
try {
const response = await fetch(url, {method: 'get'});
const data = response.json();
//use the data...
const anotherResponse = await fetch(url, {method: 'get'});
const anotherdata = anotherResponse.json();
//use the anotherdata...
} catch (error) {
console.log('Request failed', error) ;
}
Итак, на самом деле вы вызываете url после url один за другим.
Этот код будет работать в асинхронном контексте.
Вместо этого я бы использовал либо массив выборок, либо массив URL-адресов, оба в том порядке, в котором вы хотите их выполнить. Затем используйте сокращение , чтобы выполнить их последовательно. Таким образом, он намного более масштабируем.
просто некоторые способы сделать это.
1, используя асинхронный -ожидание
app.get("/getemployeedetails/:id", async (req, res) => {
const id = req.params.id;
const employeeUrl = "http://localhost:3000/employee/" + id;
try {
const response = await fetch(employeeUrl);
const employee = await response.json();
const projectUrl = "http://localhost:3000/project/" + employee.project_id;
const response1 = await fetch(projectUrl);
const project = await response1.json();
const result = {
...employee,
...project,
};
res.send(result);
} catch (error) {
console.log("getData: ", error);
}
});
2, цепочка затем
app.get("/getemployeedetails/:id", (req, res) => {
const id = req.params.id;
const employeeUrl = "http://localhost:3000/employee/" + id;
let employeeResponse = null;
fetch(employeeUrl)
.then((employee) => employee.json())
.then((resp) => {
employeeResponse = resp
const projectUrl =
"http://localhost:3000/project/" + employeeResponse.project_id;
return fetch(projectUrl);
})
.then((project) => project.json())
.then((projectResponse) => {
const result = {
...employeeResponse,
...projectResponse,
};
res.send(result);
})
.catch((err) => console.log(err));
});
3, цепочка лучше
app.get("/getemployeedetails/:id", (req, res) => {
const id = req.params.id;
getEmployeeResponse(id).then((employeeResponse) => {
getProjectResponse(employeeResponse.project_id)
.then((projectResponse) => {
const result = {
...employeeResponse,
...projectResponse,
};
res.send(result);
})
.catch((err) => console.log(err));
});
});
function getEmployeeResponse(id) {
return new Promise((resolve, reject) => {
const employeeUrl = "http://localhost:3000/employee/" + id;
fetch(employeeUrl)
.then((employee) => employee.json())
.then((resp) => resolve(resp))
.catch((err) => reject(err));
});
}
function getProjectResponse(id) {
return new Promise((resolve, reject) => {
const projectUrl = "http://localhost:3000/project/" + id;
fetch(projectUrl)
.then((project) => project.json())
.then((resp) => resolve(resp))
.catch((err) => reject(err));
});
}
Вам решать.
Разумно ли использовать такой код в javascript?
Да. Ваш код в порядке.
За исключением того, что после второго запроса
fetch(anotherUrl).then(function(response) {
, Я бы заменил
return response.json();
с участием
response.json().then(function(data2) {
- так же, как после первого запроса.
Затем переменная будет содержать тело ответа внутреннего URL-запроса, если это необходимо.
Это означает, что - что бы вы ни делали с
data2
, вы должны сделать это во втором обратном вызове (поскольку обещание не возвращается).
Кроме того, несколько распечаток помогут понять, что происходит.
1. Исходный код - немного изменен
После внесения этих изменений вот фрагмент стека, содержащий ваш код:
Ошибка, обнаруженная в конце, не может определить, какой из URL-запросов не удался.
1 Все фрагменты этого ответа соответствуют полустандартному стилю JavaScript .
Я предлагаю использовать axios, это намного лучше, и вам не нужно иметь дело с форматом JSON. Кроме того, код выглядит чище и его легче понять.
axios.get(firstUrl).then((resp1) => {
// Handle success of first api
axios.get(secondUrl).then((resp2) => {
return resp2.data
}).catch((error) => { /* Handle error of second api */ });
}).catch((error) => { /* Handle error of first api */ });
Цитата из LogRocket.com:
Как и в случае с Fetch, Axios основан на обещаниях. Однако он предоставляет более мощный и гибкий набор функций.
Преимущества использования Axios по сравнению с собственным API Fetch включают в себя:
- Перехват запросов и ответов
- Оптимизированная обработка ошибок
- Защита от XSRF
- Поддержка прогресса загрузки
- Тайм-аут ответа
- Возможность отмены запросов
- Поддержка старых браузеров
- Автоматическое преобразование данных JSON