我想编写一个从youtube视频返回信息的javascript函数;更具体一点,我想在json对象中获取搜索获得的ID和视频长度。所以我看了一下youtube API,然后我推出了这个解决方案:
function getYoutubeDurationMap( query ){
var youtubeSearchReq = "https://gdata.youtube.com/feeds/api/videos?q="+ query +
"&max-results=20&duration=long&category=film&alt=json&v=2";
var youtubeMap = [];
$.getJSON(youtubeSearchReq, function(youtubeResult){
var youtubeVideoDetailReq = "https://gdata.youtube.com/feeds/api/videos/";
for(var i =0;i<youtubeResult.feed.entry.length;i++){
var youtubeVideoId = youtubeResult.feed.entry[i].id.$t.substring(27);
$.getJSON(youtubeVideoDetailReq + youtubeVideoId + "?alt=json&v=2",function(videoDetails){
youtubeMap.push({id: videoDetails.entry.id.$t.substring(27),runtime: videoDetails.entry.media$group.media$content[0].duration});
});
}
});
return youtubeMap;
}
逻辑是正确的,但是当我调用这个函数时,你们很多人已经理解了因为ajax而得到一个空数组。反正有没有得到完整的对象?我应该使用Deferred对象吗?谢谢你的回答。
答案 0 :(得分:4)
是的,您应该使用延迟对象。
这里最简单的方法是创建一个数组,您可以在其中存储内部jqXHR
调用的$.getJSON()
结果。
var def = [];
for (var i = 0; ...) {
def[i] = $.getJSON(...).done(function(videoDetails) {
... // extract and store in youtubeMap
});
}
然后在整个函数结束时,使用$.when
创建一个新的promise,只有当所有内部调用完成时才会解析:
return $.when.apply($, def).then(function() {
return youtubeMap;
});
和然后使用.done
来处理函数的结果:
getYoutubeDurationMap(query).done(function(map) {
// map contains your results
});
有关使用此YouTube API的演示,请参阅http://jsfiddle.net/alnitak/8XQ4H/,了解延迟对象如何允许您将“AJAX”调用与“持续时间搜索”的后续数据处理完全分开。
代码有点长,但也在这里复制。但是,虽然代码比您预期的要长,但请注意,此处的通用功能现在可以重复用于您可能要对YouTube API进行的任何调用。
// generic search - some of the fields could be parameterised
function youtubeSearch(query) {
var url = 'https://gdata.youtube.com/feeds/api/videos';
return $.getJSON(url, {
q: query,
'max-results': 20,
duration: 'long', category: 'film', // parameters?
alt: 'json', v: 2
});
}
// get details for one YouTube vid
function youtubeDetails(id) {
var url = 'https://gdata.youtube.com/feeds/api/videos/' + id;
return $.getJSON(url, {
alt: 'json', v: 2
});
}
// get the details for *all* the vids returned by a search
function youtubeResultDetails(result) {
var details = [];
var def = result.feed.entry.map(function(entry, i) {
var id = entry.id.$t.substring(27);
return youtubeDetails(id).done(function(data) {
details[i] = data;
});
});
return $.when.apply($, def).then(function() {
return details;
});
}
// use deferred composition to do a search and then get all details
function youtubeSearchDetails(query) {
return youtubeSearch(query).then(youtubeResultDetails);
}
// this code (and _only_ this code) specific to your requirement to
// return an array of {id, duration}
function youtubeDetailsToDurationMap(details) {
return details.map(function(detail) {
return {
id: detail.entry.id.$t.substring(27),
duration: detail.entry.media$group.media$content[0].duration
}
});
}
// and calling it all together
youtubeSearchDetails("after earth").then(youtubeDetailsToDurationMap).done(function(map) {
// use map[i].id and .duration
});
答案 1 :(得分:0)
正如您所发现的那样,您无法直接返回youtubeMap
,因为它尚未在返回时填充。但是,您可以返回已完全填充的youtubeMap
的承诺,可以对其进行操作,例如.done(), .fail()
或.then()
。
function getYoutubeDurationMap(query) {
var youtubeSearchReq = "https://gdata.youtube.com/feeds/api/videos?q=" + query + "&max-results=20&duration=long&category=film&alt=json&v=2";
var youtubeVideoDetailReq = "https://gdata.youtube.com/feeds/api/videos/";
var youtubeMap = [];
var dfrd = $.Deferred();
var p = $.getJSON(youtubeSearchReq).done(function(youtubeResult) {
$.each(youtubeResult.feed.entry, function(i, entry) {
var youtubeVideoId = entry.id.$t.substring(27);
//Build a .then() chain to perform sequential queries
p = p.then(function() {
return $.getJSON(youtubeVideoDetailReq + youtubeVideoId + "?alt=json&v=2").done(function(videoDetails) {
youtubeMap.push({
id: videoDetails.entry.id.$t.substring(27),
runtime: videoDetails.entry.media$group.media$content[0].duration
});
});
});
});
//Add a terminal .then() to resolve dfrd when all video queries are complete.
p.then(function() {
dfrd.resolve(query, youtubeMap);
});
});
return dfrd.promise();
}
对getYoutubeDurationMap()
的调用将采用以下形式:
getYoutubeDurationMap("....").done(function(query, map) {
alert("Query: " + query + "\nYouTube videos found: " + map.length);
});
注意:
map
并显示.id
和.runtime
数据。$.when.apply(..)
响应完成,但是提取所需的数据会更加笨拙。