AngularJS:通过 promises 获取 "asynchronous" 调用的基础进展

AngularJS: obtain underlying progression of an "asynchronous" call via promises

所以,我们目前有类似这样的东西用于向后端的异步请求。

首先:GenericApi 用于所有应用程序

get: function (url) { 
        return api_bridge ({
          execute: function (auth_headers) {
            return $q.resolve($http.get(vm.urlBase + url, {headers: auth_headers}));
          } 
        }).then(handlerSuccessResponse, handlerErrorResponse);
      }

然后是处理程序方法

//error
function handlerErrorResponse(response) {     
  return $q.reject(response); 
}

//success
function handlerSuccessResponse(response) {
  if (response.isAsync) {
      return asyncStatus(response.taskId);
  } else {
      return $q.resolve(response);
  }
}  

这里成功拿到钥匙,因为如果是异步方法,就递归调用这个方法:

function asyncStatus(id){
  return getAsyncStatus(id).then(function(response){
    if (response.progress < 100){
      return asyncStatus(id); 
    } else {
      return getAsyncResult(id);
    }
  });
}

调用其中一个:

  getAsyncStatus: function(id){
    return get('/async/status/' + id);
  },

  getAsyncResult: function(id){
    return get('/async/result/' + id);
  },

(再次调用此列表的第一个方法)。

这样我们就可以做一个 getter 我们永远不会关心幕后发生的事情:

  get("/myurl")
  .then(successMethod)
  .catch(errorMethod);

(无论是否异步,这都将以相同的方式工作)

但现在我们想升级这个系统,以便能够在每次调用 asyncStatus 时进行回调。理想情况下是这样的:

  get("/myurl")
  .then(successMethod)
  .catch(errorMethod)
  .progression(progressMethod);

最明显的方法是将一个方法作为参数传递给所有链,然后在 getAsyncStatus 的每次迭代中调用它,但这种方法违背了所有方法的目的这在引擎盖下有一个黑盒子,没有人需要担心,加上改变这意味着改变所有当前现有的方法。

为了使其尽可能接近示例,我想我必须用 $q.defer().notify() 做一些事情,但我似乎无法正确理解这个概念。这样做不起作用:

  get("/myurl")
  .then(successMethod, null, progressMethod)
  .catch(errorMethod);

我不知道如何让它工作。

好吧,显然 api_bridge 方法破坏了 promise 绑定。发现解决方案是这样做的:

通用 获取:

get: function (url) { 
        var dfr = $q.defer();
        dfr.resolve( api_bridge ({
          execute: function (auth_headers) {
          return $q.resolve($http.get(vm.urlBase + url, {headers: auth_headers}));
          } 
        }));
        return dfr.promise.then(handlerSuccessResponse, handlerErrorResponse);
      }

处理程序方法(无变化):

//error
function handlerErrorResponse(response) {     
  return $q.reject(response); 
}

//success
function handlerSuccessResponse(response) {
  if (response.isAsync) {
      return asyncStatus(response.taskId);
  } else {
      return $q.resolve(response);
  }
}  

递归异步方法:

function asyncStatus(id){
  var deferred = $q.defer();
  var deferred.promise.then(null, null, angular.noop);
  var deferred.notify("This is a notification");
  deferred.resolve(getAsyncStatus(id).then(function(response){
    if (response.progress < 100){
      return asyncStatus(id); 
    } else {
      return getAsyncResult(id);
    }
  }));
  return deferred.promise;
}

调用其中任何一个(不变);

  getAsyncStatus: function(id){
    return get('/async/status/' + id);
  },

  getAsyncResult: function(id){
    return get('/async/result/' + id);
  },

现在我们可以做:

get("/myurl")
  .then(successMethod, null, progressMethod)
  .catch(errorMethod);

Callback progressMethod 将在每次 asyncStatus 抛出通知时调用。