采用了棱角分明的承诺,有效地推迟采用了、有效地、棱角、分明

2023-09-14 23:08:26 作者:不谈从前只是寒暄

在角(和所有的SPA js框架),假定页面导航是极其快速和无缝给用户。唯一的瓶颈这个速度是使用API​​调用来从服务器获取数据。因此,它似乎是合理的找到解决的办法,我们可以渲染整个页面,除了物理数据为presented,在我们等待我们的API调用来得到响应。

In Angular (and all SPA JS Frameworks), it is assumed that page navigation be extremely quick and "seamless" to the user. The only bottleneck to this speed is the use of API calls to retrieve data from our server. Therefore, it seems reasonable to find a solution where we can render an entire page, except for the physical data being presented, while we wait for our API call to get a response.

我是相当新的角度和我遇到了那些让我从实现上述目标和功能的一些问题。让我带你通过我碰到,同时学习角的2个问题

I am fairly new to Angular and I am running into a few problems that are keeping me from achieving the above goal and functionality. Let me take you through the 2 problems I came across while learning Angular

问题1:API响应太慢的角

起初,我只是从控制器中调用我的API。我有多个数据表的将要填充我收到我的反应后。该反应得到之前,我的表有一个简单的< TR> 包含一个.gif微调​​的重新presents数据的加载。我有一个设置为 A $ scope.gotAPIResponse 属性假开始,然后在API响应后,它被设置到真正

At first, I was simply calling my API from within the controller. I have multiple tables of data that are going to be populated after I receive my response. Before the response is gotten, my tables have a simple <tr> that contains a .gif "spinner" that represents the loading of data. I have a $scope.gotAPIResponse property that is set to false initially and then after the API responds, it gets set to true.

我为了显示和隐藏微调和体面表中的数据使用此布尔值。这将导致HTML成功地渲染,一切都看起来很好给用户。然而,在JavaScript控制台定睛一看,你可以看到,折角扔许多错误,因为它试图 $编译我的模板的API调用前得到了响应。错误永远不会是一件好事,所以我只好凑合。

I use this boolean in order to show and hide the "spinner" and the table data respectably. This causes the HTML to render successfully and everything looks fine to the user. However, a closer look at the JavaScript console and you can see that Angular threw many errors because it was attempting to $compile my templates BEFORE the API call got a response. Errors are never a good thing, so I had to improvise.

的在'LandingController的

function init() {

            $scope.gotAPIResponse = false;

            // Get Backup data
            API.Backups.getAll(function (data) {
                console.log(data);
                $scope.ActiveCurrentPage = 0;
                $scope.InactiveCurrentPage = 0;
                $scope.pageSize = 25;
                $scope.data = data.result;
                $scope.gotAPIResponse = true;

            });
        }

的下面是抛出错误HTML模板..无论本地模板和分页指令抛出错误的

<tbody>
     <tr ng-hide="gotAPIResponse"><td colspan="6"><p class="spinner"></p></td></tr>
     <tr ng-if="gotAPIResponse" ng-repeat="active in data.ActiveBackups | paginate:ActiveCurrentPage*pageSize | limitTo:pageSize">
               <td><a ui-sref="order.overview({ orderId: active.ServiceId })" ng-click="select(active)">{{ active.Customer }}</a></td>
               <td>{{ active.LastArchived }}</td>
               <td>{{ active.ArchiveSizeGB | number:2 }}</td>
               <td>{{ active.NumMailboxes }}</td>
               <td>{{ active.ArchivedItems }}</td>
               <td><input type="button" class="backup-restore-btn" value="Restore" /></td>
      </tr>
                </tbody>
            </table>
            <div pagination backup-type="active"></div>

问题2:使用resolve属性阻止一切

然后我仰望那就是在 $ stateProvider (UI路由器)提供的解析属性 $ routeProvider (基本角)。这让我推迟控制器,直到 $承诺在收到我的API调用的实例。

I then looked towards the resolve property that is available in the $stateProvider (ui-router) and $routeProvider (basic Angular). This allowed me to defer the instantiation of the Controller until the $promise on my API call was received.

这工作应该怎么会有和我不再收到任何错误,因为API响应可用HTML模板可能呈现前。这样做的问题然而,当你试图去那个国家或路由,整个视图将是第二个,直到 $承诺收到一个分裂不可用。这似乎滞后或块用户(这只是看起来很可怕)

This worked how it should have and I no longer received any errors because the API response was available before the HTML template could be rendered. The problem with this however, was that when you attempted to go to that state or route, the entire view would be unavailable for a split second until the $promise was received. This would appear to "lag" or "block" to the user (which just looks terrible)

的使用resolve属性的

 $stateProvider
            .state('dashboard', {
                url: '/',
                controller: 'LandingController',
                resolve: {
                    res: ['API', function(API){
                        return API.Backups.getAll(function (data) {
                            return data.result;
                        }).$promise;
                    }]
                }
            })

的那么这个控制器API调用后实例化,但是这之间的时间就像是1-2秒......这样太慢了!的

app.controller('LandingController', ['$scope', 'API', 'res',  function ($scope, API, res) {

        $scope.data = res.result;
...

解决方法:右键之间

为了解决这个问题,我们需要一个解决方案是正确的,我已经尝试过2之间。我们需要实例控制器尽可能快让 $ scope.gotAPIResponse 可设定,因此造成的DOM的微调和各地展示,但是,我们需要这样的错误不会抛出推迟HTML模板只是特定部分和其他指令。

In order to solve this, we need a solution that is right in between the 2 that I have already tried. We need to instantiate the controller as quick as possible so $scope.gotAPIResponse can be set and therefore cause the "spinner" and rest of the DOM to show, however, we need to defer just specific parts of the HTML template and other Directives so that Errors are not thrown.

是否有一个有效的解决这个问题,人们在生产中使用?

Is there an effective solution to this problem that people are using in production?

推荐答案

在结束时,这结束了一个更简单的修复。经过一番讨论后,我们重构了视图位,以避免 NG-重复的之前执行NG-如果这不期望的行为。

Update

In the end, this ended up being a much simpler fix. After some discussion we refactored the view a bit in order to avoid the ng-repeat executing before the ng-if which wasn't the desired behavior.

因此​​,而不是这样的:

So instead of this:

<tbody>
     <tr ng-if="!gotAPIResponse">
       <!-- show spinner -->
     </tr>
     <tr ng-if="gotAPIResponse" ng-repeat="stuf in stuffs">
       <!-- lots o' DOM -->
     </tr>
</tbody>

我们拉到了 NG-如果上一级这样:

We pulled the ng-if up one level to this:

<tbody ng-if="!gotAPIResponse">
     <tr >
       <!-- show spinner -->
     </tr>
</tbody>
<tbody ng-if="gotAPIResponse">
     <tr ng-repeat="stuf in stuffs">
       <!-- lots o' DOM -->
     </tr>
</tbody>

这路 NG-如果不被复制的每一行,直到条件满足将停止进一步的处理。

This way the ng-if isn't being duplicated for each row, and will halt further processing until the condition is satisfied.

这其实很简单,通过使用一个指令,并听取了他们对一些路由变化事件,实现了 $ rootScope

This is actually simple to achieve by using a directive and listening to some route change events on the $rootScope

我们的想法是在切换,可用于显示/隐藏某个元素范围的属性。在这种情况下,一个简单的载入中...的文字,但在你的情况下,它很容易被用来显示一个微调。

The idea is to toggle a property on scope that can be used to Show/Hide some element. In this case a simple "Loading..." text, but in your case it could easily be used to show a spinner.

var routeChangeSpinner = function($rootScope){
 return {
   restrict:'E',
   template:"<h1 ng-if='isLoading'>Loading...</h1>",
   link:function(scope, elem, attrs){
     scope.isLoading = false;

     $rootScope.$on('$routeChangeStart', function(){
       scope.isLoading = true;
     });
     $rootScope.$on('$routeChangeSuccess', function(){
       scope.isLoading = false;
     });
   }
 };
};
routeChangeSpinner.$inject = ['$rootScope'];

app.directive('routeChangeSpinner', routeChangeSpinner);

然后在HTML中,你会简单地做到这一点:

Then inside your HTML you would simply do this:

<div class="row">
  <!-- I will show up while a route is changing -->
  <route-change-spinner></route-change-spinner>

  <!-- I will be hidden as long as a route is loading -->
  <div ng-if="!isLoading" class="col-lg-12" ng-view=""></div>
</div>

瞧!简单的方法来显示加载指示器,同时改变路线。

Voila! Simple way to show a loading indicator while changing routes.