वेनिला जेएस का उपयोग करके एक एपीआई के साथ पुनरावृत्ति
मैं रिक और मॉर्टि एपीआई के साथ खेल रहा हूं और मैं ब्रह्मांड के सभी पात्रों को एक सरणी में लाना चाहता हूं इसलिए मुझे अपने बाकी कोड को काम करने के लिए अधिक एपीआई कॉल करने की आवश्यकता नहीं है।
समापन बिंदु 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}`))
कुछ तेज आँखें और दिमाग सहायक होगा। यह शायद वास्तव में कुछ सरल है और मैं इसे याद कर रहा हूं।
जवाब
निम्न पंक्ति में समस्याएं हैं:
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()
मैं एक और उत्तर देने में संकोच करता हूं क्योंकि ट्रिनकोट का विश्लेषण और उत्तर हाजिर है।
लेकिन मुझे लगता है कि यहाँ एक पुनरावर्ती उत्तर काफी सुरुचिपूर्ण हो सकता है। और जैसा कि सवाल "पुनरावृत्ति" के साथ टैग किया गया था, यह पेश करने के लायक लगता है।
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)
}
मैं मूल संस्करण पसंद करता हूं। लेकिन शायद आपको यह अधिक स्पष्ट लगेगा।