angularjs - 在 AngularJS 中使服务异步

标签 angularjs

请原谅我的无知,我是 Angular 和 JavaScript 的新手。 我读过, promise 使调用异步服务更加优雅,但我无法找到任何有关如何使我的服务异步的文档。

最佳答案

如果您只是简单地包装对 $http 的调用,那么您不需要做任何额外的工作。所有 $http 调用都会返回一个 Promise,因此您只需传递该 Promise,您的 API 将是异步且基于 Promise 的。

function MyService($http){
   this.$http = $http;
}

MyService.prototype = {
   getContacts: function(){
      //$http returns a promise already,
      // so just pass it along
      return $http.get('/api/contacts');
   }
};

angular.service('myService', MyService);

//Later on in some controller

function MyController(myService){
   var _this = this;

   //getContacts() returns the promise
   // from $http
   myService.getContacts()
      .success(function(contacts){
         _this.contacts = contacts;
      });
}

但是...

如果您想创建一个异步执行代码的普通 API,那么您可以将其包装在 Promise 中,就像文档中的示例一样。

JavaScript 是 basically*单线程,这意味着它使用异步代码的执行队列。执行会从上到下进行,每当停止时,队列就会按顺序清空。

当您调用诸如 setTimeoutsetInterval 之类的内容时,它只是将该代码放入队列中,以便在当前线程到达时执行,但事实并非如此。 t 在后台发生。

您可以通过打开浏览器控制台并在其中键入以下代码来自行测试:

setTimeout(function(){ console.log("I'm first!"); }, 0);
console.log("Nope, I am!");

即使我将超时设置为 0 毫秒,但这并不意味着它会立即执行。这意味着它将被放入队列中,一旦所有其他代码完成就立即运行。

终于

不要将 Promise 视为严格用于管理异步调用。它们是满足某些先决条件后执行代码的模式。碰巧,最流行的前提条件是通过 AJAX 进行异步 I/O。

但是该模式是管理任何必须等待一定数量先决条件的操作的好方法。

为了真正理解这一点,请查看这个小片段,它使用 Promise 来确定用户何时连续单击按钮超过 5 次。

(function() {

  var app = angular.module('promise-example', []);

  function PromiseBasedCounter($q, $timeout) {
    this.$q = $q;
    this.$timeout = $timeout;
    this.counter = 0;
    this.counterDef = $q.defer();
  }
  PromiseBasedCounter.$inject = ['$q', '$timeout'];
  
  PromiseBasedCounter.prototype = {
    increment: function() {
      var _this = this;

      //$timeout returns a promise, so we can
      // just pass that along. Whatever is returned
      // from the inner function will be the value of the
      // resolved promise
      return _this.$timeout(function() {

        _this.counter += 1;

        //Here we resolve the promise we created in the 
        // constructor only if the count is above 5
        if (_this.counter > 5) {
          _this.counterDef.resolve("Counter is above 5!");
        }

        return _this.counter;
      });
    },
    countReached: function() {
      //All defered objects have a 'promise' property
      // that is an immutable version of the defered
      // returning this means we can attach callbacks
      // using the promise syntax to be executed (or not)
      // at some point in the future.
      return this.counterDef.promise;
    }
  };

  app.service('promiseBasedCounter', PromiseBasedCounter);

  function ClickCtrl(promiseBasedCounter) {
    var _this = this;
    _this.promiseBasedCounter = promiseBasedCounter;
    _this.count = 0;

    //Here we set up our callback. Notice this
    // really has nothing to do with asyncronous I/O
    // but we don't know when, or if, this code will be
    // run in the future. However, it does provide an elegant
    // way to handle some precondition without having to manually
    // litter your code with the checks
    _this.promiseBasedCounter.countReached()
      .then(function(msg) {
        _this.msg = msg;
      });
  }
  ClickCtrl.$inject = ['promiseBasedCounter'];
  ClickCtrl.prototype = {
    incrementCounter: function() {
      var _this = this;

      //Whenever we increment, our service executes
      // that code using $timeout and returns the promise.
      // The promise is resolved with the current value of the counter.
      _this.promiseBasedCounter.increment()
        .then(function(count) {
          _this.count = count;
        });
    }
  };

  app.controller('clickCtrl', ClickCtrl);

}());
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div ng-app="promise-example" ng-controller="clickCtrl as ctrl">
  <div class="container">
    <h1>The current count is: <small>{{ctrl.count}}</small></h1>
    <button type="button" class="btn btn-lg btn-primary" ng-click="ctrl.incrementCounter()">Click Me!</button>
  </div>
  <div class="container">
    <h1>{{ctrl.msg}}</h1>
  </div>
</div>

关于angularjs - 在 AngularJS 中使服务异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30721646/

相关文章:

javascript - Bootstrap 启动之前的 C3 渲染

javascript - AngularJS Ng-model-options 无法在 getter-setter 函数中选择对象

AngularJS 动画基本 ng-repeat slider

javascript - ng-click 无法从 ui-grid 复选框 cellTemplate 工作

AngularJS。将标签值(Unix 时间转换为人类可读时间)

angularjs - 表单验证和用 $compile 添加的字段

angularjs - Angular 1.2 : Is it possible to exclude an input on form dirty checking?

javascript - 如何将 ng-click 项目传递到 http 的数据负载

javascript - 反转 Angular 中的排序顺序

angularjs - Angular $localStorage 不适用于 WP8