延迟 angular.js $http 服务

Posted

技术标签:

【中文标题】延迟 angular.js $http 服务【英文标题】:Delay an angular.js $http service 【发布时间】:2013-08-16 18:56:06 【问题描述】:

我有一些 angular factory 可以像这样对遗留的 ASP.NET .asmx Web 服务进行 ajax 调用:

module.factory('productService', ["$http",
function ($http) 
    return 
        getSpecialProducts: function (data) 
            return $http.post('/ajax/Products.asmx/GetSpecialProducs', data);
        
    
 ]);

我正在本地网络上进行测试,因此响应时间“太”好。有没有一种聪明的方法可以将 $http 延迟几秒钟以模拟不良连接?

或者我是否需要将所有对工厂方法的调用包装在 $timeout 中?

$timeout(function() 
  productService.getSpecialProducs(data).success(success).error(error);
, $scope.MOCK_ajaxDelay);

【问题讨论】:

【参考方案1】:

有趣的问题!

正如您自己提到的,$timeout 是延迟通话最合乎逻辑的选择。您可以推送一个响应拦截器,该响应拦截器将$http 承诺包装在$timeout 承诺中,而不是到处都有$timeout 调用,正如documentation of $http 中概念性地概述的那样,并将其注册到您的配置块之一中。这意味着所有$http 调用都会受到$timeout 延迟的影响。大致如下:

$httpProvider.interceptors.push(function($timeout) 
    return 
        "response": function (response) 
            return $timeout(function() 
                return response;
            , 2500);
        
    ;
);

作为“模拟不良连接?”的奖励,您也可以随机拒绝或完全不做任何事情。 嘿嘿嘿。

【讨论】:

胜过我的回答! - 似乎我需要阅读拦截器 如果服务器返回错误(即任何非 2XX),这将无法正常工作。在这种情况下,您还需要添加错误函数并拒绝它。 @cdmckay 当然你会处理失败的响应,但这不是问题的一部分;-)。 在哪里放置它的最佳位置,运行阶段还是配置阶段?好的,我自己回答:你不能把 $q 和 $timeout 放在配置阶段。嗯,真的吗?我放弃了…… 在较新的 AngularJS 版本中语法发生了变化。新语法为:***.com/a/31873453/232649【参考方案2】:

新的chrome设备模拟器有网络节流功能:

要到达那里:在 Google Chrome 中,按 F12 打开开发者工具。然后,在左上角,点击“切换设备模式”图标(左侧的“元素”菜单)。

【讨论】:

在我的 Chrome 中,我在“网络”选项卡上找到了用于限制的下拉菜单。无需激活设备模拟器。 问题是,如果您正在模拟数据而不是实际进行网络调用,这将不起作用【参考方案3】:

在@stevuu 的答案上进一步发展

responseInterceptors 似乎已被弃用(从 1.2.20 开始)我已修改代码以使用 interceptors 机制:

$httpProvider.interceptors.push(function($q, $timeout) 
    return 
        'response': function(response) 
            var defer = $q.defer();
            $timeout(function() 
                        defer.resolve(response);
                , 2300);
            return defer.promise;
        
    ;
);

【讨论】:

【参考方案4】:

您可以将 $q 服务用于 defer().promise 模式:

function someFunction(MOCK_ajaxDelay) 
   var deferred = $q.defer();
   $http.post('/ajax/Products.asmx/GetSpecialProducs', data).success(function(response) 
      $timeout(function() deferred.resolve( success: true, response: response ), MOCK_ajaxDelay);  
   ).error(function() 
      $timeout(function() deferred.resolve( success: true, response: response  , MOCK_ajaxDelay);  
   );
   return deferred.promise;


someService.someFunction(500).then(function(data) 
    if (data.success) 
      $scope.items = data.response.d;
    
);

但如果你真的是模拟测试,更好的解决方案是查看 ngMock:http://docs.angularjs.org/api/ngMock.$httpBackend

【讨论】:

【参考方案5】:

虽然@stevuu's 的答案是正确的,但从那时起,较新的 AngularJS 版本中的语法发生了变化。更新后的语法是:

$httpProvider.interceptors.push(["$q", "$timeout", function ($q, $timeout) 
  function slower(response) 
    var deferred = $q.defer();
    $timeout(function() 
        deferred.resolve(response);
    , 2000);
    return deferred.promise;
  
  return 
    'response': slower
  ;
]);

【讨论】:

【参考方案6】:

您可以使用 promise api 和 $timeout 来实现这一点。 $http.post 函数返回一个promise,您可以从中调用.success 和.error(这些是http 特定的方法)。当 http 请求完成时,这个 promise resolved。如果您构建自己的 Promise,那么您可以告诉它延迟 2 秒,然后在 http 请求完成时解析:

module.factory('productService', function ($http, $q, $timeout) 

    return 
        getSpecialProducts: function (data) 
            var defer = $q.defer();
            $http.post('/ajax/Products.asmx/GetSpecialProducs', data).success(
              function(data) 
                // successful http request, resolve after two seconds
                $timeout(function() 
                    defer.resolve(data);
                , 2000)
            ).error(function() 
                defer.reject("Http Error");
            )
            return defer.promise;
        
    

);

但请注意 - 您必须使用 promise.then(successCallback, errorCallback) 功能 - 也就是说,您将无法从控制器/指令访问 http 标头、状态和配置,除非您明确将它们提供给传递给 @987654326 的对象@

链接:

Defer/Promise Api Http/Promise Api Resolve egghead video

【讨论】:

【参考方案7】:

针对您的问题的测试方面,Fiddler 有一个非常有用的功能,可以在您需要模拟延迟时提供帮助:

    单击 Fiddler 中的“自动回复”选项卡。 使用与您要延迟的请求的 URL 匹配的正则表达式添加规则。 将“respond with”设置为“*delay:1000”,其中数字是以毫秒为单位的延迟。

Fiddler 中的 AutoResponder 功能对于测试涉及大量 http 请求的 JS 非常有用。您可以将其设置为响应特定的 http 错误代码、阻止响应等。

【讨论】:

我假设您使用的是 Windows,因为使用了 asp.net 网络服务。【参考方案8】:

如果您正在使用返回承诺的服务,那么您也应该在 $timeout 之前放置一个 return,因为这只会返回另一个承诺。

return dataService.loadSavedItem(
    save_id: item.save_id,
    context: item.context
).then(function (data) 
    // timeout returns a promise
    return $timeout(function () 
        return data;
    ,2000);
);

希望它对某人有所帮助!

【讨论】:

以上是关于延迟 angular.js $http 服务的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Angular.js 中延迟路由定义?

angular中ng-repeat是啥意思

angular js $http服务使用

如何在 Angular js 的选项卡集中启用延迟加载?

Yeoman Angular.js grunt serve-d 应用程序从 livereload.js?snipver=1 延迟很长

Angular.js 提交表单的旧方式