我在多个异步调用方面遇到问题。我有三项任务想要申请。首先我从第一个请求中获取一些 json 数据。然后,当该请求完成时,我从另一个服务发出多个请求以获取电影预告片,并将该数据合并到第一个响应中的每个对象。当所有这些都完成后,我想将该数据写入 json 文件。很简单,但我没有兑现 promise 。
这是我的代码
MovieService.getContent(config.url + '?key=' + config.moviekey).then(function(data) {
var movies = JSON.parse(data);
var cnt = 0;
var len = movies.length;
var results = [];
for (var i = 0; i < movies.length; i++) {
var imdbid = movies[i].ids.imdb;
(function (i, imdbid) {
MovieService.getContent(config.themoviedburl + 'tt' + imdbid + '/videos?api_key=' + config.themoviedbkey).then(function (data) {
len--;
movies[i].trailers = JSON.parse(data);
if (len === 0) {
FileService.writeToJson(JSON.stringify(movies), config.showtimesfilepath);
}
});
})(i, imdbid);
};
});
现在这可以工作了,但是如果循环中的一个请求失败怎么办?那么我的计数器不正确,我会将数据写入文件。有人可以帮我使用 promise 来设置类似的场景吗?哦,是的,我的代码的另一个亮点是 MovieService 女巫发出所有请求
最佳答案
使用 Promise 对数组上的一系列操作进行排序的常见方法是使用 .reduce()
,其中每次迭代都会添加到 Promise 链上,从而对所有异步操作进行排序:
// in sequence
MovieService.getContent(config.url + '?key=' + config.moviekey).then(function(data) {
var movies = JSON.parse(data);
return movies.reduce(function(p, movie, index) {
return p.then(function() {
var imdbid = movie.ids.imdb;
return MovieService.getContent(config.themoviedburl + 'tt' + imdbid + '/videos?api_key=' + config.themoviedbkey).then(function (data) {
movies[index].trailers = JSON.parse(data);
}, function(err) {
// handle the error here and decide what should be put into movies[index].trailers
});
});
}, Promise.resolve()).then(function() {
return FileService.writeToJson(JSON.stringify(movies), config.showtimesfilepath);
});
});
从概念上讲,它的作用是调用 movies.reduce()
并且传递到 .reduce()
的起始值是一个已解决的 promise 。然后,通过 .reduce()
的每次迭代都会使用 p = p.then(...)
之类的内容添加到 Promise 链中。这会导致所有操作按顺序排列,等待一个操作完成后再调用下一个操作。然后,在该 .then()
处理程序内部,它返回 MovieService.getContent()
Promise,以便此迭代也将等待内部 Promise 完成。
您也可以并行执行这些操作,而无需强制它们按顺序排列。您只需要知道它们何时完成,并且需要保持所有数据有序。可以这样做:
// in parallel
MovieService.getContent(config.url + '?key=' + config.moviekey).then(function(data) {
var movies = JSON.parse(data);
var promises = [];
movies.forEach(function(movie, index) {
var imdbid = movie.ids.imdb;
promises.push(MovieService.getContent(config.themoviedburl + 'tt' + imdbid + '/videos?api_key=' + config.themoviedbkey).then(function (data) {
movies[index].trailers = JSON.parse(data);
}, function(err) {
// handle the error here and decide what should be put into movies[index].trailers
}));
});
Promise.all(promises).then(function() {
return FileService.writeToJson(JSON.stringify(movies), config.showtimesfilepath);
});
});
或者,使用 Bluebird 的 Promise 库的有用的 Promise.map()
,这是一个更短的并行版本
// use Bluebird's Promise.map() to run in parallel
MovieService.getContent(config.url + '?key=' + config.moviekey).then(function(data) {
var movies = JSON.parse(data);
Promise.map(movies, function(movie, index) {
var imdbid = movie.ids.imdb;
return MovieService.getContent(config.themoviedburl + 'tt' + imdbid + '/videos?api_key=' + config.themoviedbkey).then(function (data) {
movies[index].trailers = JSON.parse(data);
}, function(err) {
// handle the error here and decide what should be put into movies[index].trailers
});
}).then(function() {
return FileService.writeToJson(JSON.stringify(movies), config.showtimesfilepath);
});
});
如果您希望即使任何给定的请求失败也能继续该过程,那么您必须描述在这种情况下您希望发生的情况,并且可以通过处理 .getContent() 上的错误来实现
这样它总是返回一个已解决的 promise 。
关于javascript - 多个异步调用回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34253855/