javascript - How do I utilize $.Deferred() / Promise() properly in this case? -


the problem tested in debugger, go in first function (up $.get() without getting yet) skip second function (once again, $.get()). then, proceed execute first function till it's finished retrieving items, when gets second function, same thing mysterious reason, videoidchainstr holds video ids in string first function never retrieved or being executed since suspected, executed second function's $.get(...) , never did again "second time" when had values. resolve that, thought of async operations , it's bit confusing @ first after reading articles, understand some, not 100%, , not in code yet, tried code below:

i want understand how use $.deferred, resolve(), , promise() in case , if applicable, other methods then(), since need resolve , promise return filled value (videoidchainstr) done() needed , executes second function thereafter.

first function:

var relatedvidsdefer = function relatedvids(videoid) {     var videoidchainstr = null;     var deferredval = $.deferred(); // instantiate defer object      $.get( // related videos related videoid         "https://www.googleapis.com/youtube/v3/search",         {             part: 'snippet',             maxresults: vidresults,             relatedtovideoid: videoid,             order: 'relevance',             type: 'video',             key: 'xxxxxxx'         },          function(data)         {             $.each(data.items,                 function(i, item)                 {                     try                     {                         console.log(item);                         var vidtitle = item.snippet.title; // video title                          var vidthumburl = item.snippet.thumbnails.default.url;                          var channeltitle = item.snippet.channeltitle;                         var extractvideoid = null; // var extract video id string vidthumburl                          // check if vidthumburl not null, empty string, or undefined                         if(vidthumburl)                         {                             var split = vidthumburl.split("/"); // split string when '/' seen                             extractvideoid = split[4]; // retrieve fourth index on fourth '/'                         }                         else console.error("vidthumburl either undefined or null or empty string.");                          // if video title longer 25 characters, insert three-dotted ellipse                         if(vidtitle.length > 25)                         {                             var strnewvidtitle = vidtitle.substr(0, 25) + "...";                             vidtitle = strnewvidtitle;                         }                              // check whether channeltitle same                         if(channeltitle === "channel name")                         {                             extractedvideoidarr.push(extractvideoid); // add extracted video id array                              // check if extractedvideoidarr not empty                             if(extractedvideoidarr !== 'undefined' && extractedvideoidarr.length > 0)                             {                                 videoidchainstr = extractedvideoidarr.join(", "); // change array chain string of videoids relatedvidsdetails()                              }                             deferredval.resolve(videoidchainstr); // value                               var vidthumbnail = '<div class="video-thumbnail"><a class="thumb-link" href="single-video.html"><div class="video-overlay"><img src="imgs/video-play-button.png"/></div><img src="' + vidthumburl + '" alt="no image available." style="width:204px;height:128px"/></a><p><a class="thumb-link" href="single-video.html">' + vidtitle + '</a><br/></div>';                              // print results                             $('.thumb-related').append(vidthumbnail);                             $(item).show(); // show current video thumbnail item                          }                         else $(item).hide(); // hide current video thumbnail item                     }                     catch(err)                     {                         console.error(err.message); // log error continue operation                         }                 }             );          }     );     return deferredval.promise(); // return value , execute second function }; 

second function:

var relatedvidsdetailsdefer = function relatedvidsdetails(videoidchainstr) {     // change extractvideoid string tostring() or join() param recognize     console.log("initial: ", extractedvideoidarr);     $.get(         "https://www.googleapis.com/youtube/v3/videos",         {             part: 'snippet, contentdetails, statistics',             id: videoidchainstr, // chain string of video ids called upon in single request             key: 'xxxxxxx',         },          function(data)         {             $.each(data.items,                 function(i, item)                 {                     try                     {                         var _vidduration = item.contentdetails.duration;                         var _viewcount = item.statistics.viewcount;                         console.log("id: " + extractedvideoidarr[i] + " duration: " + _vidduration);                         console.log("id: " + extractedvideoidarr[i] + " viewcount: " + _viewcount);                          $('.viddetails').append(convert_time(_vidduration) + ' / views: ' + _viewcount);                     }                     catch(err)                     {                         console.error(err.message); // log error continue operation                         }                 }             );         }     ); }; 

execution:

relatedvidsdefer(_videoid).done(relatedvidsdetailsdefer); // wait till first function (before .done parameter) complete before executing second (in .done paramater) 

update:

code updated @valarauko's answer. finally, worked , able retrieve videos' details 1 of videos duplicated rest of videos. upon entering second function, videoidchainstr has first id , not rest... i'm assuming, deferredval.resolve(videoidchainstr); resolve right away when gets id first time in first function's loop, not rest of string, though continues loop , resolve items.

for example: suppose pass id1, id2, id3 parameter, passed id1. why went through each loop on second function once. how fix occurrence?

the reason why second function executing before because appending parenthesis function inside done statement (this executes inmediately function , assigns result of function in done callback.

relatedvidsdefer(_videoid).done(relatedvidsdetailsdefer()); 

should be

relatedvidsdefer(_videoid).done(relatedvidsdetailsdefer); 

also don't know if using videoidchainstr global variable on purpose recommend make locally , feed relatedvidsdetailsdefer function receives parameter (no change should done first function since resolving promise string.

the second function like

var relatedvidsdetailsdefer = function relatedvidsdetails(videoidchainstr) {...} 

update

if @ jquery deferred documentation (link), resolved/rejected promise ignore future calls resolve/reject , return data used on first resolved/rejected. notice had 1 done statement checking first 1 anyway.

for particular problem can modify second function receive array of strings , resolve promise array of strings.


Comments