Angular没有使用promises

时间:2016-02-05 02:33:10

标签: javascript angularjs node.js asynchronous promise

我正在尝试使用Angular服务来调用使用fs.readFilefs.writeFile,具体取决于按下的按钮类型,以便了解节点和角度承诺如何交互。我所拥有的是阅读写入文件,但不会发回读取数据,也不会让我理解错误。

//HTML
<button ng-click="rw('write')">WRITE FILE</button>
<button ng-click="rw('read')">READ FILE</button>


//angular
angular.module('test', [])
  .controller('ctrl', function($scope, RWService){
    $scope.rw = function(type){
      RWService.rw(type)
      .then(
        function(res){
          console.log('success');
      }, 
        function(err){
          console.log('error');
      })
    };
  })
  .service('RWService',['$http', '$q', function($http, $q){
    this.rw = function(type){
      var promise = $http.get('./rw/' + type);
      var dfd = $q.defer();
      promise.then(
        function(successResponse){
          dfd.resolve(successResponse);
        }, 
        function(errorResponse){
          dfd.reject(errorResponse);
        }
      );
      return dfd.promise;
    };
  }]);

 //node
var fs = require('fs')
  , async = require('async')
  , Q = require('Q');

var dest = './file.txt';

var rw = {
    write: function(data){
    data = data.repeat(5);
    return Q.nfcall(fs.writeFile, dest, data);
  }
  , read: function(data){
    data = data.repeat(5);
    var deferred = Q.defer();
    console.log('inside read');
    fs.readFile(dest, 'utf8', function(err, data){
      if (err){
        deferred.reject('some error');
      }else{
        deferred.resolve(data);
      }
    });
    return deferred.promise;
  }
};

module.exports = exports = rw;

//node server
app.get('/rw/:type', function(req, res, next){
  var type = req.params.type;
  var data = 'some text string\n';
  if (type == 'write'){
    //omitted fro brevity
  }else{
    rw.read(data)
    .then(function(response){
      return {'response': response};
    })
    .catch(function(err){
      return {'index.js error': err};
    });
  }
});

我将this blog post的角度$q部分组织起来。

1 个答案:

答案 0 :(得分:1)

这是您的代码的本机Promise实现。

var fs = require('fs');

var dest = './file.txt';

var rw = {
    write: function(data){
        return new Promise(function (resolve, reject) {
            data = data.repeat(5);

            fs.writeFile(function (err, result) {
                if (err) return reject(err.message);

                return resolve(result);
            });
        });
    },
    read: function(data){
        return new Promise(function (resolve, reject) {
            data = data.repeat(5);

            fs.readFile(dest, 'utf8', function(err, contents) {
                if (err) return reject(err.message);

                return resolve(contents.toString());
            });
        });
    }
};

module.exports = exports = rw;

[编辑:我刚刚更改了代码,将data=data.repeat(5)放在promise工厂方法中。基本上,如果有任何CAN引发异常,你应该尝试将它放在promise函数中,否则你再次冒险再次以静默方式杀死脚本。]

几条评论:

返回deferred非常有用,但您必须小心使用它。我个人只使用它,如果异步代码不能包装在一个简单的函数中(例如在其构造函数中创建promise并在不同的子方法中解析/拒绝的类实例)。在您的情况下,可能正在发生的事情是脚本失败的方式fs.readFile()永远不会被调用 - 因此永远不会达到deferred.resolve()deferred.reject()。在这种情况下,您需要使用try / catch并始终在其中调用deferred.reject()。这是一项很容易避免的额外工作。

相反,您应该尝试使用Promises的vanilla标准实现,如上所示。

最后,Q是一个开创性的图书馆,它基本上教会了世界如何做出承诺,但它没有多年更新,也从未特别丰富或快速。如果您需要更多功能,请查看when.js *,kew或Bluebird(请注意Bluebird声称速度最快,但我个人认为这是不真实的。)

(*我实际上喜欢使用when.js并且使用愚蠢的原生承诺发现它有点痛苦,但是嘿,标准是标准。)

[编辑:添加有关Angular方面的详细信息]

因此根据您的评论,我怀疑您也在寻找。你会看到我在这里使用$http.get()作为唯一的承诺。一旦进入承诺,就不需要使用defer(),所以实际上甚至不需要包含$q

对不起,我从未使用service()。甚至Angular自己的创建服务文档都使用factory()方法,这就是我在这里使用的方法。

.factory('RWService',['$http', function($http){
    return {
        rw: function (type) {
            // $http returns a promise. No need to create a new one.
            return $http.get('./rw/' + type)
            .then(function (response) {
                // You can do other stuff here. Here, I am returning the
                // contents of the response. You could do other stuff as
                // well. But you could also just omit this `then()` and 
                // it would be the same as returning just the response.
                return response.data;
            })
            .catch(function (err) {
                // You can do other stuff here to handle the error.
                // Here I am rethrowing the error, which is exactly the
                // same as not having a catch() statement at all.
                throw err;
            });
        }
    };
}]);

如果您阅读上面代码中的注释,您应该意识到您可以编写相同的代码:

.factory('RWService',['$http', function($http){
    return {
        rw: function (type) {
            return $http.get('./rw/' + type);
        }
    };
});

唯一的区别是RWService.rw()最终将解析整个响应对象而不是响应数据。

要记住的是,你可以(而且绝对应该)尽可能地回收你的承诺。基本上,你需要知道的所有承诺是:

  1. 每个承诺都有thencatch方法,您可以将逻辑包装在其中;
  2. 每个thencatch都会作为新承诺返回;
  3. 如果您在任何thencatch内引发异常,您将被直接转到下一个catch,如果有的话;
  4. 如果您从任何thencatch返回一个值,它将作为参数传递给链中的下一个then;
  5. 当链条耗尽then或者您抛出异常并且不再有catch es时,承诺链结束;和
  6. thencatch速度很快,但它们仍然是异步的,因此如果您真的不需要,请不要将新元素添加到承诺链中。