Javascript 从具有嵌套ajax调用的函数返回对象

Javascript 从具有嵌套ajax调用的函数返回对象,javascript,jquery,ajax,jquery-deferred,Javascript,Jquery,Ajax,Jquery Deferred,我想写一个javascript函数,返回来自youtube视频的信息;更具体地说,我想在json对象中获取通过搜索获得的ID和视频长度。因此,我查看了youtube API,并提出了以下解决方案: function getYoutubeDurationMap( query ){ var youtubeSearchReq = "https://gdata.youtube.com/feeds/api/videos?q="+ query + "&a

我想写一个javascript函数,返回来自youtube视频的信息;更具体地说,我想在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;    

    }
函数GetYouTube教育地图(查询){
变量youtubeSearchReq=”https://gdata.youtube.com/feeds/api/videos?q=“+查询+
“&max results=20&duration=long&category=film&alt=json&v=2”;
var youtubeMap=[];
$.getJSON(youtubeSearchReq,函数(youtubeResult){
变量youtubeVideoDetailReq=”https://gdata.youtube.com/feeds/api/videos/";

对于(var i=0;iYes),应该使用延迟对象

这里最简单的方法是创建一个数组,您可以在其中存储内部
$.getJSON()
调用的
jqXHR
结果

var def = [];
for (var i = 0; ...) {
    def[i] = $.getJSON(...).done(function(videoDetails) {
        ... // extract and store in youtubeMap
    });
}
然后在整个函数的末尾,使用
$。当
创建一个新的承诺时,该承诺将仅在所有内部调用完成后才能解决:

return $.when.apply($, def).then(function() {
    return youtubeMap;
});
然后使用
.done
处理函数的结果:

getYoutubeDurationMap(query).done(function(map) {
    // map contains your results
});
有关使用此YouTube API的演示,请参阅。该演示演示了延迟对象如何允许您将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
});

是的,您应该使用延迟对象

这里最简单的方法是创建一个数组,您可以在其中存储内部
$.getJSON()
调用的
jqXHR
结果

var def = [];
for (var i = 0; ...) {
    def[i] = $.getJSON(...).done(function(videoDetails) {
        ... // extract and store in youtubeMap
    });
}
然后在整个函数的末尾,使用
$。当
创建一个新的承诺时,该承诺将仅在所有内部调用完成后才能解决:

return $.when.apply($, def).then(function() {
    return youtubeMap;
});
然后使用
.done
处理函数的结果:

getYoutubeDurationMap(query).done(function(map) {
    // map contains your results
});
有关使用此YouTube API的演示,请参阅。该演示演示了延迟对象如何允许您将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
});

正如您所发现的,您不能直接返回
youtubeMap
,因为它在返回点还没有填充。但是您可以返回一个完全填充的
youtubeMap
,可以使用例如
.done()、.fail()
.then()
执行

调用
GetYouTubeEducationMap()
的形式如下:

getYoutubeDurationMap("....").done(function(query, map) {
    alert("Query: " + query + "\nYouTube videos found: " + map.length);
});
注:

  • 实际上,您可能会在
    map
    中循环,并显示
    .id
    .runtime
    数据
  • 顺序查询比并行查询更好,因为顺序查询对客户端和服务器都更友好,而且更可能成功
  • 另一种有效的方法是返回一组单独的承诺(每个视频一个),并在完成时使用
    $.when.apply(..)
    ,但是提取所需的数据会比较困难

正如您所发现的,您不能直接返回
youtubeMap
,因为它在返回点尚未填充。但是您可以返回一个完全填充的
youtubeMap
的承诺,可以使用例如
.done()、.fail()
.then()
来执行

调用
GetYouTubeEducationMap()
的形式如下:

getYoutubeDurationMap("....").done(function(query, map) {
    alert("Query: " + query + "\nYouTube videos found: " + map.length);
});
注:

  • 实际上,您可能会在
    map
    中循环,并显示
    .id
    .runtime
    数据
  • 顺序查询比并行查询更好,因为顺序查询对客户端和服务器都更友好,而且更可能成功
  • 另一种有效的方法是返回一组单独的承诺(每个视频一个),并在完成时使用
    $.when.apply(..)
    ,但是提取所需的数据会比较困难

不,你应该提出一个同步请求。但不要这样做:学会使用Javascript的异步逻辑,你也可以做很多其他事情。在回调时执行事情……是的,你应该使用延迟对象。更多背景信息:不,你应该提出一个同步请求。但不要这样做:学会使用asynchronous的Javascript逻辑,你也可以处理很多其他事情。在回调时执行事情…是的,你应该使用延迟对象。更多背景信息:不错,但根据我的经验,串联运行查询会使批处理速度变慢,浏览器应该将并发AJAX查询的数量限制在4个左右如果它们是并行运行的。是的,它会运行得更慢,但更能保证完成。在这方面,我还没有对浏览器行为做过全面的回顾,但我不会对所有浏览器都施加保护。记住,现在有很多流行的“还rans”,特别是在Linux领域(包括Raspberry PI)-Midori、Dillo、Chromium、NetSurf、IceWeasel……它们的行为如何?我不知道。不错,但根据我的经验,以串联方式运行查询会使批处理速度变慢,如果并行运行,浏览器应该将并发AJAX查询的数量限制在4个左右。是的,它会运行得更慢,但更能保证不会o完成。在这方面,我还没有对浏览器行为做过全面的评估,但我不会对所有的浏览器都施加保护。请记住,现在有很多流行的“还rans”,特别是在Linux领域(包括树莓PI)——Midori、Dillo、Chromium、NetSurf、IceWeasel。。。