Rekursi dengan API, menggunakan Vanilla JS

Aug 18 2020

Saya bermain dengan Rick and Morty API dan saya ingin memasukkan semua karakter alam semesta ke dalam array sehingga saya tidak perlu membuat lebih banyak panggilan API untuk mengerjakan sisa kode saya.

Endpoint https://rickandmortyapi.com/api/character/mengembalikan hasil di halaman, jadi saya harus menggunakan rekursi untuk mendapatkan semua data dalam satu panggilan API.

Saya bisa mendapatkannya untuk memuntahkan hasil ke HTML tetapi saya tidak bisa mendapatkan array lengkap objek JSON.

Saya menggunakan beberapa ide dari rekursi Axios untuk membuat halaman api dengan kursor

Saya menerjemahkan konsep untuk masalah saya, dan saya sudah memasangnya di Codepen saya. Ini kodenya:

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

Beberapa mata dan otak yang tajam akan membantu. Ini mungkin sesuatu yang sangat sederhana dan saya melewatkannya.

Jawaban

3 trincot Aug 18 2020 at 13:34

Baris berikut bermasalah:

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

Di sini Anda memasukkan objek promise ke dalam allPeople, dan saat .push()mengembalikan angka, Anda mengembalikan angka, bukan allPeople.

Menggunakan forloop ke pushitem individual dari satu array ke array lainnya benar-benar merupakan cara verbose untuk menyalin sebuah array. Perulangan hanya diperlukan untuk bagian HTML.

Juga, Anda bercampur .then()dengan await, yang membuat segalanya menjadi rumit. Gunakan awaitsaja. Saat menggunakan await, tidak perlu rekursi lagi. Cukup ganti ifdengan satu lingkaran:

while (info) {
   ....
   info = res.data.info.next;
}

Anda tidak pernah menetapkan apapun universePeople. Anda dapat menghapus parameter ini.

Alih-alih forloop biasa , Anda dapat menggunakan for...ofsintaks.

Karena resAnda hanya menggunakan dataproperti, gunakan variabel untuk properti itu saja.

Jadi dengan menggabungkan semua itu, Anda mendapatkan ini:

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

Berikut adalah contoh kerja untuk fungsi rekursif

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

Saya ragu untuk menawarkan jawaban lain karena analisis dan jawaban Trincot tepat.

Tapi saya pikir jawaban rekursif di sini bisa sangat elegan. Dan karena pertanyaan itu ditandai dengan "rekursi", sepertinya pertanyaan itu layak untuk disajikan.

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>

Ini hanya berkaitan dengan pengambilan data. Menambahkannya ke DOM Anda harus menjadi langkah terpisah, dan seharusnya tidak sulit.

Pembaruan: Penjelasan

Sebuah komentar menunjukkan bahwa ini sulit diurai. Ada dua hal yang menurut saya mungkin rumit di sini:

  • Pertama adalah destructuring objek di {info: {next}, results} = <...>. Ini hanyalah cara yang bagus untuk menghindari penggunaan variabel perantara untuk menghitung variabel yang sebenarnya ingin kita gunakan.

  • Yang kedua adalah sintaks penyebaran dalam return [...results, ...<more>]. Ini adalah cara yang lebih sederhana untuk membangun larik daripada menggunakan .concatatau .push. (Ada fitur serupa untuk objek.)

Berikut versi lain yang melakukan hal yang sama, tetapi dengan beberapa variabel perantara dan rangkaian array sebagai gantinya. Itu melakukan hal yang sama:

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

Saya lebih suka versi aslinya. Tetapi mungkin Anda akan menemukan yang satu ini lebih jelas.