在解决控制器依赖关系时保持AngularJS的响应性

在解决控制器依赖关系时保持AngularJS的响应性,angularjs,coffeescript,dependencies,promise,angular-ui-router,Angularjs,Coffeescript,Dependencies,Promise,Angular Ui Router,AngularJS在等待任何承诺的控制器依赖项解决时停止处理UI事件。如果这些依赖项中的任何一个依赖于挂起的API调用,则应用程序将变得无响应 如何设计一个AngularJS应用程序,在ui路由器解决外部控制器依赖关系时保持响应 咖啡脚本示例: 注入accountBase的/accounts/:account\u id的路由定义: 控制器示例 在AngularJS中加载数据时,您有很多选择。以下三种方法对数据的呈现和可见性都有不同的影响 解析(在路由或状态中)-根据定义,这将停止页面的呈现,直

AngularJS在等待任何承诺的控制器依赖项解决时停止处理UI事件。如果这些依赖项中的任何一个依赖于挂起的API调用,则应用程序将变得无响应

如何设计一个AngularJS应用程序,在ui路由器解决外部控制器依赖关系时保持响应

咖啡脚本示例: 注入
accountBase
/accounts/:account\u id
的路由定义: 控制器示例
在AngularJS中加载数据时,您有很多选择。以下三种方法对数据的呈现和可见性都有不同的影响

  • 解析(在路由或状态中)-根据定义,这将停止页面的呈现,直到所有解析值都完成加载。在您的示例中,您返回一个承诺,即ui路由器将在开始呈现/执行控制器函数之前解析哪个ui路由器。根据我的经验,最好少用这些,因为它们会导致一种波涛汹涌的体验

  • 在控制器中,使用$resource并将get/query的返回值直接绑定到$scope

     var Foo = $resource('/api/foos'); // inject this into your controller
    
     // inside your controller function...
     $scope.foos = Foo.query();
    
    这将导致在$scope上放置一个空对象,一旦可用,它将被来自API调用的数据填充。这可能是可取的,也可能不是可取的,这取决于您正在显示的内容。在模板中,您可以检查$resolved属性
    ng show=“foos.$resolved”
    ,以显示数据正在加载的某种视觉提示。(另外,我不确定Restangular是否提供相同类型的“空对象”返回值,或者它是否只返回承诺。)

    值得注意的是:您也可以用同样的方式使用解析。由于将返回一个对象(虽然该对象包含一个承诺,但不是一个承诺),因此渲染/控制器函数执行不会被延迟:

    resolve: {
        foos: function(Foo) {
            return Foo.query();
        }
    }
    
  • 为要显示的数据提供一些默认值,然后对$http或$resource调用使用success函数来填充实际值

    $scope.data = {
        stuff: "none yet",
        things: "still waiting"
    };
    
    // when the data is available, replace the defaults.
    Foo.get({id: 1}, function(data) {
        angular.extend($scope.data, data);  
    });    
    
还有几件值得注意的事情:

  • 缓存数据,以便用户下次访问该页面/路由时,您可以获得一个过时的副本。过时的数据通常比没有数据好。您可以使用在本地存储中存储东西,以实现跨会话的可用性—非常方便
  • 若要在当前会话中保留数据,请使用单例来保留对数据的引用。任何注入以下服务的操作都将获得相同的对象实例(本例中为数组)

    这是一个过于简单的示例,但是您可以返回一个包装器对象,该对象提供用于操作/重新加载数据的函数

希望这有帮助

更新

值得一提的是,您的示例代码向后弯曲了一点以加载accountBase。因为您使用
deferred.resolve(base)解析解析函数中的承诺,您的控制器被注入已解决的承诺。为了清楚起见,您可以执行
deferred.resolve(结果),以便将
result
的值直接注入控制器


我刚刚查看了,我发现您可以返回promise的$object属性,以获得由$resource返回的相同类型的“要填充的空对象”,这将在不阻止渲染的情况下立即解决,等等。

在AngularJS中加载数据时,您有很多选择。以下三种方法对数据的呈现和可见性都有不同的影响

  • 解析(在路由或状态中)-根据定义,这将停止页面的呈现,直到所有解析值都完成加载。在您的示例中,您返回一个承诺,即ui路由器将在开始呈现/执行控制器函数之前解析哪个ui路由器。根据我的经验,最好少用这些,因为它们会导致一种波涛汹涌的体验

  • 在控制器中,使用$resource并将get/query的返回值直接绑定到$scope

     var Foo = $resource('/api/foos'); // inject this into your controller
    
     // inside your controller function...
     $scope.foos = Foo.query();
    
    这将导致在$scope上放置一个空对象,一旦可用,它将被来自API调用的数据填充。这可能是可取的,也可能不是可取的,这取决于您正在显示的内容。在模板中,您可以检查$resolved属性
    ng show=“foos.$resolved”
    ,以显示数据正在加载的某种视觉提示。(另外,我不确定Restangular是否提供相同类型的“空对象”返回值,或者它是否只返回承诺。)

    值得注意的是:您也可以用同样的方式使用解析。由于将返回一个对象(虽然该对象包含一个承诺,但不是一个承诺),因此渲染/控制器函数执行不会被延迟:

    resolve: {
        foos: function(Foo) {
            return Foo.query();
        }
    }
    
  • 为要显示的数据提供一些默认值,然后对$http或$resource调用使用success函数来填充实际值

    $scope.data = {
        stuff: "none yet",
        things: "still waiting"
    };
    
    // when the data is available, replace the defaults.
    Foo.get({id: 1}, function(data) {
        angular.extend($scope.data, data);  
    });    
    
还有几件值得注意的事情:

  • 缓存数据,以便用户下次访问该页面/路由时,您可以获得一个过时的副本。过时的数据通常比没有数据好。您可以使用在本地存储中存储东西,以实现跨会话的可用性—非常方便
  • 若要在当前会话中保留数据,请使用单例来保留对数据的引用。任何注入以下服务的操作都将获得相同的对象实例(本例中为数组)

    这是一个过于简单的示例,但是您可以返回一个包装器对象,该对象提供用于操作/重新加载数据的函数

希望这有帮助

更新

值得一提的是,您的示例代码向后弯曲了一点以加载accountBase。因为您使用
deferred.resolve(base)解析解析函数中的承诺,您的控制器被注入