我遇到了一些愚蠢的架构,因为我很笨。我正在尝试浏览发布到Reddit的YouTube视频,提取网址并将其处理为.m3u播放列表。
的完整代码在某些时候,我认为我可以检查每个网址,看看视频是否已经死亡,并提供替代方案,如果它们已被移除。
所以我对YouTube API做了AJAX请求,如果出现错误,我应该对它做出反应并更改该项目的URL。
但问题是它只有在AJAX不是异步的情况下才有效 - 这需要很多秒,在此期间页面会被卡住。
我想让AJAX保持异步,但我不知道应该如何构建代码。
以下是 PSEUDOCODE :
var listing = // data from reddit API
$.each(listing, function(key, value) {
var url = // post URL from reddit posts listing
// ( "http://youtu.be/XmQR4_hDtpY&hd=1" )
var aRegex = // to parse YouTube URLs
// ( (?:youtube(?:-nocookie)?.com/....bla...bla )
var videoID = // YouTube video ID, extracted with regex
// ( "XmQR4_hDtpY" )
var itemArtist = // parsed from reddit posts listing
// ( "Awesome Artist" )
var itemTitle = // parsed from reddit posts listing
// ( "Cool Song (Original Mix)" )
var itemURL = // url, further processed
// ( "3dydfy://www.youtube.com/watch?v=XmQR4_hDtpY&hd=1" )
$.ajax({
type: "HEAD",
url: "https://gdata.youtube.com/feeds/api/videos/" + videoID,
error: function() {
// If it's no longer available
// (removed, deleted account, made private)
deadVid++; // chalk up another dead one, for showing progress
itemURL = // dead videos should get a different URL
// ( "3dydfy-search://q=Awesome%20Artist%20Cool%20Song....." )
}
});
// further process itemURL!
// at this point I want itemURL changed by the .ajax()'s error callback
// but I'm trying to keep the requests async
// to not jam the page while a hundred HTTP requests happen!
if (condition){
itemURL += // append various strings
}
// Write the item to the .m3u8 playlist
playlist += itemURL + '\n';
}// end .each()
答案 0 :(得分:4)
基本上你想知道
如果您将错误推送到列表中,结果将在结束时准备就绪(当然不能保证顺序)。
对于第二部分,如果你保留从每个$ .ajax返回的ajax promise的数组,你可以使用$.when
并等待它们全部使用always()
完成。
作为基本示例(删除了其他详细信息):
var listing = {}; // data from reddit API
var promises = [];
var results = [];
$.each(listing, function(key, value) {
// [snip]
promises.push($.ajax({
type: "HEAD",
url: "https://gdata.youtube.com/feeds/api/videos/" + videoID,
error: function() {
//[snip]
results.push({
itemArtist: itemArtist,
videoID: videoID,
url: itemURL});
}
});
);
}
// Wait for all promises to complete (pass or fail)
$.when.apply($, promises).always(function(){
// process list of failed URLs
});
为任何拼写错误道歉。这直接编码到答案中,但你明白了。
我注意到你提到了100个请求,但浏览器一次只允许少量通过,所以不需要额外的处理。
如果always
无效,您可以添加自己的延迟对象,这些对象可在success
或 fail
上解析:
var listing = {}; // data from reddit API
var promises = [];
var results = [];
$.each(listing, function(key, value) {
var deferred = $.Deferred();
promises.push(deferred.promise());
// [snip]
$.ajax({
type: "HEAD",
url: "https://gdata.youtube.com/feeds/api/videos/" + videoID,
complete: function(){
// resolve on success or fail
deferred.resolve();
},
error: function() {
//[snip]
results.push({
itemArtist: itemArtist,
videoID: videoID,
url: itemURL});
}
});
);
}
// Wait for all promises to complete (pass or fail)
$.when.apply($, promises).always(function(){
// process list of failed URLs
});
这是另一种很好的方法,可以将并行承诺链接在一起,而不使用数组(只要您不需要传递给回调的数据值):
简化代码:
var promise; // Undefined is also a resolved promise when passed to $.when()
$.each(listing, function(key, value) {
// Each new Ajax promise is chained, in parallel, with the previous promise
promise = $.when(promise, $.ajax({...}));
});
// When they are all finished, fire a final callback
$.when(promise).always(function(){
// All done!
});
这引起了一些批评,主要来自那些认为它是“不洁净”的人,但是为了简化并行承诺代码,权衡是最小的。
当我看到有人使用promise = promise.then(newpromise)
按顺序链接事件时,我发现这是可能的。经过一些实验,我发现我可以使用promise = $.when(promise, newpromise)