如果$ http.get()没有产生新数据,请使AngularJS跳过运行摘要循环

Str*_*lle 14 javascript optimization ajax-polling angularjs

我当前正在轮询服务器以检查新数据,然后相应地更新AngularJS应用程序中的模型.他大致正在做的事情:

setInterval(function () {
    $http.get('data.json').then(function (result) {
        if (result.data.length > 0) {
          // if data, update model here
        } else {
          // nothing has changed, but AngularJS will still start the digest cycle
        }
    });
}, 5000);
Run Code Online (Sandbox Code Playgroud)

这很好,但大多数请求不会导致任何新的数据或数据更改,但$ http服务并不真正知道/关心,仍然会触发摘要周期.我认为这是不必要的(因为摘要周期是应用程序中最重的操作之一).有没有办法仍然可以使用$ http,但如果没有任何改变,以某种方式跳过摘要?

一种解决方案是不使用$ http而是使用jQuery,然后调用$ apply让Angular知道模型已经改变:

setInterval(function () {
    $.get('data.json', function (dataList) {
        if (dataList.length > 0) {
            // if data, update model
            $scope.value = dataList[0].value + ' ' + new Date();

            // notify angular manually that the model has changed.
            $rootScope.$apply();
        }
    });
}, 5000);
Run Code Online (Sandbox Code Playgroud)

虽然这似乎有效,但我不确定这是个好主意.如果可能的话,我仍然想使用纯Angular.

任何人都有任何改进上述方法的建议或完全更优雅的解决方案?

PS我之所以使用setInterval而不是$ timeout是因为$ timeout也会触发一个摘要周期,在这种情况下这是不必要的,只会增加"问题".

Dra*_*usu 8

  1. AngularJS @doc提供的解决方案

AngularJS建议使用PERF技巧,通过$ httpProvider在一个$ digest中捆绑一些$ http响应.这再次,不是解决问题,它只是一种镇静剂:)

$httpProvider.useApplyAsync(true)
Run Code Online (Sandbox Code Playgroud)
  1. 保存$$观察者解决方案 - 风险且不可扩展

首先,接受的解决方案是不可扩展的 - 你不可能在100K行的JS代码项目上做那个$ watchers技巧 - 这是不可能的.

其次,即使项目很小,风险很大!例如,如果另一个ajax呼叫到达实际需要那些观察者的情况会发生什么?


  1. 另一个(可行的)风险解决方案

在不修改AngularJS代码的情况下实现此目的的唯一方法是将$ rootScope.$$阶段设置为true或'$ digest',进行$ http调用,并将$ rootScope.$$阶段设置为null.

 $rootScope.$$phase = true;
 $http({...})
   .then(successcb, failurecb)
   .finally(function () {
       $rootScope.$$phase = null;            
   });
Run Code Online (Sandbox Code Playgroud)

风险:

1)其他ajax调用可能会尝试做同样的事情 - >他们需要通过包装ajax服务(超过$ http)进行同步

2)用户可以触发两者之间的UI操作,将$$阶段更改为null的操作以及ajax调用将返回时的操作,并仍然触发$ digest

扫描AngularJS源代码后弹出解决方案 - 这是保存情况的行:https://github.com/angular/angular.js/blob/e5e0884eaf2a37e4588d917e008e45f5b3ed4479/src/ng/http.js#L1272


  1. 理想的解决方案

因为这是每个人都面对AngularJS的问题,我认为需要系统地解决.上面的答案并没有解决问题,只是试图避免它. 所以我们应该创建一个AngularJS拉取请求,允许我们通过$ httpProvider指定一个不会触发特定$ http请求的摘要的配置.希望他们同意这需要以某种方式解决.


pow*_*000 1

Web 套接字似乎是这里最优雅的解决方案。这样你就不需要轮询服务器。当数据或任何内容发生更改时,服务器可以通知您的应用程序。