【问题标题】:Using $http after previous $http done在之前的 $http 完成后使用 $http
【发布时间】:2015-01-21 21:48:06
【问题描述】:

我有 3 个 JSON Web 服务应该在我的应用程序中使用, 我使用$http 从 URL 加载,我的代码是:

$http.get('http://{url}/users')
    .then(function (result) {
        storeUsers(result);
    });

$http.get('http://{url}/news')
    .then(function (result) {
        storeNews(result);
    });

$http.get('http://{url}/pages')
    .then(function (result) {
        storePages(result);
    });

var users = getUsers();

问题:

1- 所有$http 一起运行,不要等到前面的$http 完成。

2- var users = getUsers(); 将在 $http 完成之前运行。

更新: 我将代码更改为:

 var loadedService = {
            users: false,
            news: false,
            pages: false
        };

function getUsers() {
            deferred = $q.defer();
            $http.get('http://{url}/users')
                .then(function (result) {
                    loadedService.users = result;
                    deferred.resolve('I got users');
                    console.log("Get users");
                });
            return deferred.promise;
        }

function getNews() {
            deferred = $q.defer();
            $http.get('http://{url}/news')
                .then(function (result) {
                    loadedService.news = result;
                    deferred.resolve('I got news');
                    console.log("Get news");
                });
            return deferred.promise;
        }

function getPages() {
            deferred = $q.defer();
            $http.get('http://{url}/pages')
                .then(function (result) {
                    loadedService.pages = result;
                    deferred.resolve('I got pages');
                    console.log("Get pages");
                });
            return deferred.promise;
        }


getNews().then(getUsers()).then(getPages()).then(function () {
     console.log('Done !');
});

当我运行我的程序时,我会看到:

XHR finished loading: GET "http://{url}/pages". ionic.bundle.js:16185
Get pages sync.js:133
XHR finished loading: GET "http://{url}/users". ionic.bundle.js:16185
Get users sync.js:56
XHR finished loading: GET "http://{url}/news". ionic.bundle.js:16185
Get news sync.js:107

如您所见,首先加载了pages 服务,然后是users 服务,然后是news,而在我的代码中我说的是getNews().then(getUsers()).then(getPages())

最后console.log('Done !'); 不显示!

【问题讨论】:

  • 你应该使用promises,当一个http promise被解析时执行下一个http请求
  • 感谢@Avraam,但我该如何使用承诺?我是 AngularJS 的新手

标签: javascript ajax angularjs


【解决方案1】:

您可以使用 MajoB 或 Muhammad 建议的方法之一,或者您可以使用 3 个返回 promise 的函数并按照您想要的顺序链接它们。

function getUsers(){
    deferred = $q.defer()

    $http.get('http://{url}/users')
    .success(function (result) {
        storeUsers(result);
        deferred.resolve('I got users')
    }).error(function(data, status, headers, config) {
      // called if an error occurs
      console.log('error');
      deferred.reject(status)
    });

    return deferred.promise
}

function getNews(){
    deferred = $q.defer()

    $http.get('http://{url}/news')
    .success(function (result) {
        storeUsers(result);
        deferred.resolve('I got news')
    }).error(function(data, status, headers, config) {
      // called if an error occurs
      console.log('error');
      deferred.reject(status)
    });

    return deferred.promise
}


function getPages(){
    deferred = $q.defer()

    $http.get('http://{url}/pages')
    .success(function (result) {
        storePages(result);
        deferred.resolve('I got pages')
    }).error(function(data, status, headers, config) {
      // called if an error occurs
      console.log('error');
      deferred.reject(status)
    });;


    return deferred.promise
} 

例如,假设您想在获得新闻后获得页面:

getNews().then(getPages())

在错误情况下拒绝承诺并在链接上进行错误处理更好:

getNews().then(function() {
  console.log('Success');
  getPages();
}, function() {
  console.log('Failed');
}, function() {
  console.log('Executing... ');
});

当然链也返回一个你可以处理的承诺。

【讨论】:

  • 您的解决方案是正确的,因为这样代码看起来好多了,但您还应该展示 OP 如何链接这些承诺。
  • @MarekSadura 我更新了,希望现在更清楚了。
  • @Avraam 谢谢,我用这种方式,但我得到了ReferenceError: $q is not defined
  • @MajAfy 你应该在你的指令或控制器中注入$q 服务。请参阅此处的依赖注入 docs.angularjs.org/guide/di 和此处的 $q 服务 docs.angularjs.org/api/ng/service/$q 。如果您有问题,请使用您使用 $http 的完整代码更新您的问题,我会更新我的答案。
  • @Avraam 我认为这段代码不使用队列来请求服务,因为我在第一个函数中加载了一个大尺寸的服务,然后当我在 chrome 中观看控制台时加载另一个服务,第二个服务会先加载,然后第一个服务再加载(因为第一个服务大约是8MB,第二个服务是120KB)
【解决方案2】:

如果我正确理解你的问题,你可以使用这样的东西:

$http.get('http://{url}/users')
  .then(function (result) {
    storeUsers(result);

    return $http.get('http://{url}/news');
  })
  .then(function (result) {
    storeNews(result);

    return $http.get('http://{url}/pages');
  })
  .then(function (result) {
    storePages(result);

    users = getUsers();
  });

$http.get 将返回承诺。

更新:

或更干净的解决方案:

var deferred = $q.defer(),
    users;

$http.get('http://{url}/users')
  .then(function (result) {
    storeUsers(result);

    return $http.get('http://{url}/news');
  })
  .then(function (result) {
    storeNews(result);

    return $http.get('http://{url}/pages');
  })
  .then(function (result) {
    storePages(result);

    deferred.resolve(result);
  });

 deferred.promise.then(function() {
   users = getUsers();
 });

更新2

或更简单:

var request1 = $http.get('http://{url}/users'),
    request2 = $http.get('http://{url}/news'),
    request3 = $http.get('http://{url}/pages');

$q.all([request1, request2, request3]).then(function(result) {
  storeUsers(result[0]);
  storeNews(result[1]);
  storePages(result[2]);

  users = getUsers();
}

但你还需要处理拒绝案例。

【讨论】:

    【解决方案3】:

    你可以试试这个:

    NoticeService.observeReqUser().then(null,null,function(){
        $http.get('http://{url}/users')
            .then(function (result) {
                storeUsers(result);
                NoticeService.notifyStatusOne()
            });
    });
    
    NoticeService.observeReqOne().then(null,null,function(){
        $http.get('http://{url}/news')
            .then(function (result) {
                storeNews(result);
                NoticeService.notifyStatusTwo()
            });
    });
    
    NoticeService.observeReqTwo().then(null,null,function(){
        $http.get('http://{url}/pages')
            .then(function (result) {
                storePages(result);
            });
    });
    
    var users = getUsers();
    

    您需要创建一个服务来通知请求已完成,以便可以调用下一个服务

    app.service('NoticeService',['$q',function($q){
        var noticegetUserIsDone = $q.defer();
    
        this.observeReqUser = function() { return noticegetUserIsDone.promise; };
        this.notifyStatusUser = function() { noticegetUserIsDone.notify(); };
    
        var noticeReqOneIsDone = $q.defer();
        this.observeReqOne = function() { return noticegetUserIsDone.promise; };
        this.notifyStatusOne = function() { noticegetUserIsDone.notify(); };
    
        var noticeReqTwoIsDone = $q.defer();
        this.observeReqTwo = function() { return noticegetUserIsDone.promise; };
        this.notifyStatusTwo = function() { noticegetUserIsDone.notify(); };
    };
    

    您需要从 getUser 函数的末尾调用 NoticeService.notifyStatusUser,以便链开始执行(不要忘记在调用它的位置添加 NoticeService 的引用)

    【讨论】:

      【解决方案4】:

      您可以通过将代码放入成功承诺中,使$http 请求一个接一个地运行。

      var users; // declare `users` variable
      $http.get('http://{url}/users')
          .then(function (result) {
              storeUsers(result);
      
              // second ajax request
              $http.get('http://{url}/news')
                  .then(function (result) {
                      storeNews(result);
                      // third ajax request goes here
                      // .....
      
      
                      // set the value for users
                      users = getUsers();
                  });
          });
      

      【讨论】:

      • 谢谢,我想到了,但合乎逻辑和真实吗?
      【解决方案5】:

      这里有一个使用 promises 和 angularJs 的小测试脚本

      $scope.myXhr = function(){
      
      var deferred = $q.defer();
      
      $http({
          url: 'ajax.php',
          method: "POST",
          data:postData,
          headers: {'Content-Type': 'application/x-www-form-urlencoded'}
          })
          //if request is successful
          .success(function(data,status,headers,config){
      
              //resolve the promise
              deferred.resolve("request successful");
      
          })
          //if request is not successful
          .error(function(data,status,headers,config){
              //reject the promise
              deferred.reject("ERROR");
          });
      
      //return the promise
      return deferred.promise;
      }
      
      $scope.callXhrAsynchronous = function(){
      
      var myPromise = $scope.myXhr();
      
      // wait until the promise return resolve or eject
      //"then" has 2 functions (resolveFunction, rejectFunction)
      myPromise.then(function(resolve){
          alert(resolve);
          }, function(reject){
          alert(reject)      
      });
      
      }
      

      【讨论】:

        【解决方案6】:

        您可以链接您的请求:

               $http.get('http://{url}/users')
                .then(function (result) {
                    storeUsers(result);
                    $http.get('http://{url}/news')
                        .then(function (newsResult) {
                            storeNews(newsResult);
                            $http.get('http://{url}/pages')
                                .then(function (pagesResult) {
                                storePages(pagesResult);
                            });
                        });
                });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-04
          • 1970-01-01
          • 2021-01-24
          • 2020-04-20
          • 2020-10-20
          • 1970-01-01
          相关资源
          最近更新 更多