वेनिला जेएस का उपयोग करके एक एपीआई के साथ पुनरावृत्ति

Aug 18 2020

मैं रिक और मॉर्टि एपीआई के साथ खेल रहा हूं और मैं ब्रह्मांड के सभी पात्रों को एक सरणी में लाना चाहता हूं इसलिए मुझे अपने बाकी कोड को काम करने के लिए अधिक एपीआई कॉल करने की आवश्यकता नहीं है।

समापन बिंदु https://rickandmortyapi.com/api/character/परिणामों को पृष्ठों में लौटाता है, इसलिए मुझे एक एपीआई कॉल में सभी डेटा प्राप्त करने के लिए पुनरावर्तन का उपयोग करना होगा।

मैं इसे HTML में परिणाम निकालने के लिए प्राप्त कर सकता हूं लेकिन मुझे JSON ऑब्जेक्ट्स का एक पूरा सरणी नहीं मिल सकता है।

मैं एक कर्सर के साथ एक एपीआई पेजिंग के लिए Axios पुनर्संरचना से कुछ विचारों का उपयोग कर रहा हूँ

मैंने अपनी समस्या के लिए अवधारणा का अनुवाद किया, और मैंने इसे अपने कोडपेन पर पोस्ट किया है यह कोड है:

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

एक सरणी से दूसरे में अलग-अलग मदों के 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;
    }
}
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

मैं एक और उत्तर देने में संकोच करता हूं क्योंकि ट्रिनकोट का विश्लेषण और उत्तर हाजिर है।

लेकिन मुझे लगता है कि यहाँ एक पुनरावर्ती उत्तर काफी सुरुचिपूर्ण हो सकता है। और जैसा कि सवाल "पुनरावृत्ति" के साथ टैग किया गया था, यह पेश करने के लायक लगता है।

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 में जोड़ना एक अलग कदम होना चाहिए, और यह मुश्किल नहीं होना चाहिए।

अद्यतन: स्पष्टीकरण

एक टिप्पणी ने संकेत दिया कि यह पार्स करना कठिन है। दो चीजें हैं जो मुझे लगता है कि यहाँ मुश्किल हो सकती हैं:

  • सबसे पहले वस्तु को नष्ट करना है {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)
}

मैं मूल संस्करण पसंद करता हूं। लेकिन शायद आपको यह अधिक स्पष्ट लगेगा।