Vanilla JS를 사용하는 API를 사용한 재귀

Aug 18 2020

저는 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}`))

날카로운 눈과 두뇌가 도움이 될 것입니다. 아마 정말 간단한 것 같고 그냥 놓치고 있습니다.

답변

3 trincot Aug 18 2020 at 13:34

다음 줄에 문제가 있습니다.

return allPeople.push(populatePeople(res.data.info.next, allPeople))

여기서 약속 객체를으로 푸시하고 숫자 allPeople.push()반환하면 allPeople.

한 배열에서 다른 배열 forpush개별 항목에 루프를 사용하는 것은 실제로 배열을 복사하는 장황한 방법입니다. 루프는 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;
    }
}
3 UbeytDemir Aug 18 2020 at 13:17

다음은 재귀 함수의 작동 예입니다.

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()
2 ScottSauyet Aug 18 2020 at 20:03

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)
}

나는 원래 버전을 선호합니다. 그러나 아마도 당신은 이것이 더 명확하다는 것을 알게 될 것입니다.