Vanilla JS를 사용하는 API를 사용한 재귀
저는 Rick and Morty API를 사용하고 있으며 모든 우주의 문자를 배열로 가져 와서 나머지 코드를 작업하기 위해 더 많은 API 호출을 할 필요가 없습니다.
끝점 https://rickandmortyapi.com/api/character/
은 결과를 페이지로 반환하므로 한 번의 API 호출로 모든 데이터를 가져 오려면 재귀를 사용해야합니다.
결과를 HTML로 뱉어 낼 수는 있지만 JSON 객체의 완전한 배열을 얻을 수없는 것 같습니다.
커서로 API를 페이지 매기기 위해 Axios 재귀의 아이디어를 사용하고 있습니다.
내 문제에 대한 개념을 번역하고 내 Codepen에 게시했습니다. 이것은 코드입니다.
async function populatePeople(info, universePeople){ // Retrieve the data from the API
let allPeople = []
let check = ''
try {
return await axios.get(info)
.then((res)=>{
// here the current page results is in res.data.results
for (let i=0; i < res.data.results.length; i++){
item.textContent = JSON.stringify(res.data.results[i])
allPeople.push(res.data.results[i])
}
if (res.data.info.next){
check = res.data.info.next
return allPeople.push(populatePeople(res.data.info.next, allPeople))
}
})
} catch (error) {
console.log(`Error: ${error}`) } finally { return allPeople } } populatePeople(allCharacters) .then(data => console.log(`Final data length: ${data.length}`))
날카로운 눈과 두뇌가 도움이 될 것입니다. 아마 정말 간단한 것 같고 그냥 놓치고 있습니다.
답변
다음 줄에 문제가 있습니다.
return allPeople.push(populatePeople(res.data.info.next, allPeople))
여기서 약속 객체를으로 푸시하고 숫자 allPeople
를 .push()
반환하면 allPeople
.
한 배열에서 다른 배열 for
로 push
개별 항목에 루프를 사용하는 것은 실제로 배열을 복사하는 장황한 방법입니다. 루프는 HTML 부분에만 필요합니다.
또한를 혼합 .then()
하여 await
일을 복잡하게 만듭니다. 그냥 사용하십시오 await
. 를 사용하면 await
더 이상 재귀가 필요하지 않습니다. 를 if
루프로 바꾸십시오 .
while (info) {
....
info = res.data.info.next;
}
에 아무것도 할당하지 않습니다 universePeople
. 이 매개 변수를 삭제할 수 있습니다.
일반 for
루프 대신 for...of
구문을 사용할 수 있습니다 .
로부터으로 res
만 사용 data
속성을 해당 속성 만 변수를 사용합니다.
이 모든 것을 종합하면 다음과 같은 결과를 얻을 수 있습니다.
async function populatePeople(info) {
let allPeople = [];
try {
while (info) {
let {data} = await axios.get(info);
for (let content of data.results) {
const item = document.createElement('li');
item.textContent = JSON.stringify(content);
denizens.append(item);
}
allPeople.push(...data.results);
info = data.info.next;
}
} catch (error) {
console.log(`Error: ${error}`)
} finally {
section.append(denizens);
return allPeople;
}
}
다음은 재귀 함수의 작동 예입니다.
async function getAllCharectersRecursively(URL,results){
try{
const {data} = await axios.get(URL);
// concat current page results
results =results.concat(data.results)
if(data.info.next){
// if there is next page call recursively
return await getAllCharectersRecursively(data.info.next,results)
}
else{
// at last page there is no next page so return collected results
return results
}
}
catch(e){
console.log(e)
}
}
async function main(){
let results = await getAllCharectersRecursively("https://rickandmortyapi.com/api/character/",[])
console.log(results.length)
}
main()
Trincot의 분석과 답변이 정확하기 때문에 다른 답변을 제공하는 것을 주저합니다.
그러나 여기서 재귀 적 대답은 매우 우아 할 수 있다고 생각합니다. 그리고 질문에 "재귀"태그가 지정되었으므로 제시 할 가치가있는 것 같습니다.
const populatePeople = async (url) => {
const {info: {next}, results} = await axios .get (url)
return [...results, ...(next ? await populatePeople (next) : [])]
}
populatePeople ('https://rickandmortyapi.com/api/character/')
// or wrap in an `async` main, or wait for global async...
.then (people => console .log (people .map (p => p .name)))
.catch (console .warn)
.as-console-wrapper {max-height: 100% !important; top: 0}
<script>/* dummy */ const axios = {get: (url) => fetch (url) .then (r => r .json ())} </script>
이것은 데이터를 가져 오는 것과 관련이 있습니다. DOM에 추가하는 것은 별도의 단계 여야하며 어렵지 않아야합니다.
업데이트 : 설명
분석하기 어렵다는 의견이 있습니다. 여기에서 까다로울 수있는 두 가지 사항이 있습니다.
첫 번째는이다 개체 destructuring 에서
{info: {next}, results} = <...>
. 이것은 우리가 실제로 사용하고자하는 변수를 계산하기 위해 중간 변수를 사용하지 않는 좋은 방법입니다.두 번째는 인 확산 구문 에서
return [...results, ...<more>]
. 이것은 사용하는 것보다 배열을 구축 할 수있는 간단한 방법입니다.concat
또는.push
. (객체에도 비슷한 기능이 있습니다.)
동일한 작업을 수행하는 다른 버전이 있지만 일부 중간 변수와 배열 연결이 대신 사용됩니다. 같은 일을합니다.
const populatePeople = async (url) => {
const response = await axios .get (url)
const next = response .info && response .info .next
const results = response .results || []
const subsequents = next ? await populatePeople (next) : []
return results .concat (subsequents)
}
나는 원래 버전을 선호합니다. 그러나 아마도 당신은 이것이 더 명확하다는 것을 알게 될 것입니다.