my data which is fetched from youtube is using nodejs is –
[ { title: 'Dil Zaffran Video Song | Rahat Fateh Ali Khan | Ravi Shankar | Kamal Chandra | Shivin | Palak', id: 'vChX3XZXqN4', view: '28652353' }, { title: 'Full Video: Akh Lad Jaave | Loveyatri | Aayush S|Warina H |Badshah, Tanishk Bagchi,Jubin N, ,Asees K', id: 'e_vl5aFXB4Q', view: '17328447' }]
Now I want to search 5 related videos to each video
my api
getVids(videosID) .then(result => { console.log(result) //this is the data which I showed above result.sort((a,b) => b.view - a.view); return result; }) .then(result => { return result.map(function(el) { // console.log(el); let o = Object.assign({}, el); o.relatedVideos = relatedVideos(el.id); //function is called below return o; }); }) .then(result => { console.log(result); }) .catch(err => { console.log(err) })
and api to 5 related Videos is given below
function relatedVideos(videoId) { return new Promise((resolve, reject) => { let urls = 'https://www.googleapis.com/youtube/v3/search?relatedToVideoId=' + videoId + '&key=' + API_KEY + '&part=snippet&type=video'; request(urls, (err, result) => { const data = JSON.parse(result.body); const relatedVideos = []; data.items.forEach(related => { relatedVideos.push({ title: related.snippet.title }); if(relatedVideos.length === 5){ resolve(relatedVideos); } }); }); }); }
It is giving the output like
[ { title: 'Dil Zaffran Video Song | Rahat Fateh Ali Khan | Ravi Shankar | Kamal Chandra | Shivin | Palak', id: 'vChX3XZXqN4', view: '28655496', relatedVideos: Promise { <pending> } }, { title: 'Full Video: Akh Lad Jaave | Loveyatri | Aayush S|Warina H |Badshah, Tanishk Bagchi,Jubin N, ,Asees K', id: 'e_vl5aFXB4Q', view: '17334681', relatedVideos: Promise { <pending> } }]
How to solve this pending
problem or how to wait so it gets full data.
Advertisement
Answer
It happens because you assign the promise returned by relatedVideos()
to the property relatedVideos
, you never actually wait for it to resolve. You need to await all of the promises before you proceed, this is most easily done with Promise.all()
. Let’s focus on this part of your code:
return result.map(function(el) { // console.log(el); let o = Object.assign({}, el); o.relatedVideos = relatedVideos(el.id); //function is called below return o; });
What you need to do is to wait for each promise to resolve in order to get its resolved value before you assign it to the object. Then you also need to create a promise that doesn’t resolve until all of those promises have resolved. This is what Promise.all()
is for. Change the code mentioned above into this:
return Promise.all(result.map(function(el) { // console.log(el); let o = Object.assign({}, el); return relatedVideos(el.id) .then(function(relatedVideo) { o.relatedVideos = relatedVideo; return o; }); }));
Please note that ALL of the promises mapped to Promise.all()
needs to resolve in order for the chain to continue with the next then
. If even one of those promises rejects or don’t resolve at all it will never continue. You have a condition for your resolve()
call in the relatedVideos()
function. This implies that in some cases a promise might end up never resolving. You should always resolve or reject a promise, perhaps resolve(null)
would be appropriate in your case.