JavaScript (angular) 中的承诺

Promise in JavaScript (angular)

我对 angular 和 http 调用还很陌生。

然后我读了一些关于 Promise to ync calls 的内容。我根本无法理解。 所以我需要一些帮助才能知道我是否在朝着正确的方向前进。

我正在编写一个 API 用于获取视频,以及有关它们的详细信息(观看次数等)的 Youtube API v3。

但是我似乎在获取详细信息时出错,因为我的数组一直都是空的。

    /*var promises = [];*/ // PROMISE
                var videometrics;
                var videodetails = [];
                var deferred = $q.defer();

                $http.get('https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=' + playlistId + '&key=AIzaSyDQv-WpATIWLinCB3H_sH4W1sKx7plyvRA')
                    .success(function (response) {

                        for (var i = 0; i < response.items.length; i++) {
                            var video = {
                                id: response.items[i].snippet.resourceId.videoId,
                                title: response.items[i].snippet.title
                            };
                            $scope.video.push(video)


                        }
                        /*console.log($scope.video)
                        var promises = [];*/
                        for (i = 0; i < $scope.video.length; i++) {
                            /*console.log("looping")
                            console.log($scope.video)
                            console.log("Vi henter fra id:")
                            console.log($scope.video[i].id)*/
                            $http.get('https://www.googleapis.com/youtube/v3/videos?part=statistics&id=' + $scope.video[i].id + '&key=AIzaSyDQv-WpATIWLinCB3H_sH4W1sKx7plyvRA')
                                .success(function (responsevideo) {
                                    /*console.log($scope.video[i].id);*/

                                    //                                console.log("we are in the metric loop")
                                    //                                console.log($scope.video[i].id)
                                    //                                console.log($scope.video[i].title)
                                    //                                console.log(responsevideo)
                                        videometrics = {
                                            id: responsevideo.items[0].id,
                                            views: responsevideo.items[0].statistics.viewCount,
                                            likes: responsevideo.items[0].statistics.likeCount,
                                            dislikes: responsevideo.items[0].statistics.dislikeCount,
                                            favorites: responsevideo.items[0].statistics.favoriteCount,
                                            comments: responsevideo.items[0].statistics.commentCount
                                        };
                                    videodetails.push(videometrics);
                                    deferred.resolve(responsevideo);
                                    /*detailsOnVideos = $scope.videometrics;*/

                                })
                           /* videodetails.push(videometrics);*/
                        }
                        /*promises.push(videodetails);*/ // PROMISE

                        console.log(videodetails);
                       /* console.log(promises);*/ //PROMISE LOGGER
 /*                       console.log(videodetails);*/
                        console.log($scope.video);
                        console.log("")
                        pagetokenarr = response.nextPageToken;
                        console.log(pagetokenarr)

                    });
                return deferred;
                /*return $q.all(promises);*/ // PROMISE

如您所见,我的第一个 http get 是有效的,但下一个不是。我不明白为什么。但是,如果我将我的 videodetails 数组推入一个 promise 数组,它就可以工作。然后再次。我不知道为什么。

您的代码似乎工作正常。我删除了除必需品以外的所有内容,添加了我需要的变量作为占位符,因为我不确定 playlistId 等。这是我测试过的代码。

var app = angular.module('app', []); 
app.controller('ctrl', function ($scope, $http) {
var videometrics;
$scope.videodetails = [];
var playlistId = "PL63F0C78739B09958";
$scope.video = [];
$http.get('https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=' + playlistId + '&key=AIzaSyDQv-WpATIWLinCB3H_sH4W1sKx7plyvRA')
    .success(function (response) {
        for (var i = 0; i < response.items.length; i++) {
            var video = {
                id: response.items[i].snippet.resourceId.videoId,
                title: response.items[i].snippet.title
            };
            $scope.video.push(video);
        }
        for (i = 0; i < $scope.video.length; i++) {
            $http.get('https://www.googleapis.com/youtube/v3/videos?part=statistics&id=' + $scope.video[i].id + '&key=AIzaSyDQv-WpATIWLinCB3H_sH4W1sKx7plyvRA')
            .success(function (responsevideo) {
                var videometrics = {
                    id: responsevideo.items[0].id,
                    views: responsevideo.items[0].statistics.viewCount,
                    likes: responsevideo.items[0].statistics.likeCount,
                    dislikes: responsevideo.items[0].statistics.dislikeCount,
                    favorites: responsevideo.items[0].statistics.favoriteCount,
                    comments: responsevideo.items[0].statistics.commentCount
                };
                $scope.videodetails.push(videometrics);
            });
        }
    });
});

这将在范围内可用时使用 {{videodetails}} 在浏览器中显示。

如果您需要处理数据而不是仅仅显示数据,您可能需要使用其他答案建议的服务。

$http 不需要 $q。基本上有两种方法(据我所知)可以使用 $http:

1) 创建一个服务,在那里隔离 $http。 Return 这样的承诺:

return $http.get({params...}).then(function(data) {
     return data.result;
 });

然后在控制器中你将拥有:

SuperService.get(params...).then(function(data) { $scope.something = data; });

2) 数据绑定!做一个服务,把 $http 放在那里。但是这次您将结果绑定到服务内的一个对象。在该服务中,您还有一个 return 该对象的方法。

$http.get({params...}).then(function(data) {
     myObject = data.result;
 });

然后在控制器中:

$scope.spiderman = SuperService.getObj();
SuperService.get(params...);

当您调用 .get() 时,AngularJS 发挥它的魔力并更新 $scope.spiderman(当然,一旦您收到服务器的响应)。

相关文献:

这是一个适用于此 plunker

的解决方案

您的代码运行良好。问题是你的 console.log() 被解雇得太早了,因为它不在你的承诺的 .success().then() 中。它在 $http 调用解决之前被触发。

我修改了一些你的代码(特别是论文 for 循环)以使其更具可读性。

此外,在 $http 调用 return promises

之前,您不需要构建自己的 promise

这是最终代码:

$http.get('https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=' + playlistId + '&key=AIzaSyDQv-WpATIWLinCB3H_sH4W1sKx7plyvRA')
    .success(function (response) {
        angular.forEach(response.items, function(item){
            var video = {
                  id: item.snippet.resourceId.videoId,
                  title: item.snippet.title
            };  
            $scope.video.push(video);
        }) 
        console.log($scope.video);
        angular.forEach($scope.video, function(video){
          httpcalls.push($http.get('https://www.googleapis.com/youtube/v3/videos?part=statistics&id=' + video.id + '&key=AIzaSyDQv-WpATIWLinCB3H_sH4W1sKx7plyvRA')
                .success(function (responsevideo) {
                  videometrics = {
                            id: responsevideo.items[0].id,
                            views: responsevideo.items[0].statistics.viewCount,
                            likes: responsevideo.items[0].statistics.likeCount,
                            dislikes: responsevideo.items[0].statistics.dislikeCount,
                            favorites: responsevideo.items[0].statistics.favoriteCount,
                            comments: responsevideo.items[0].statistics.commentCount
                        };
                    $scope.videodetails.push(videometrics);
                }));
        });
        pagetokenarr = response.nextPageToken;
        $q.all(httpcalls).then(function(){
          console.log($scope.videodetails);
        }) 

    });

请注意,我将所有 $http 调用放入一个集合 (httpcalls) 并将您的 console.log 包装到 $q.all(httpcalls).then() 函数中。这将等到对集合的所有 $http 调用都已解决。

希望对您有所帮助。