【问题标题】:Angular not getting data from FS.readFile with promisesAngular 没有通过承诺从 FS.readFile 获取数据
【发布时间】:2016-05-14 21:52:09
【问题描述】:

我正在尝试使用 Angular 服务来调用 fs.readFile 或 fs.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 部分。

【问题讨论】:

  • 你使用的是什么版本的节点?我个人觉得 Q 很难使用,并且从 0.12 开始,promise 就已经原生于节点。
  • @Andrew 4.0.0。是的,我只是在使用严格的承诺,对如何在没有回调的情况下做到这一点做出最好的猜测。但我肯定愿意接受你的任何建议!谢谢。

标签: javascript angularjs node.js asynchronous promise


【解决方案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 函数中,或者你再次冒着再次默默地杀死脚本的风险。]

几个cmets:

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

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

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

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


[编辑:在 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;
            });
        }
    };
}]);

如果你阅读了上面代码中的 cmets,你应该意识到你可以像这样编写相同的代码:

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

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

这里要记住的是,您可以(并且绝对应该)尝试尽可能多地回收您的承诺。基本上,关于 Promise,你只需要知道:

  1. 每个 Promise 都有一个 then 和 catch 方法,您可以将逻辑包装在其中;
  2. 每个then 和catch 都作为新的承诺返回;
  3. 如果您在任何then 或catch 中抛出异常,您将直接被抛出到下一个catch(如果有的话);
  4. 如果您从任何then 或catch 返回值,它将作为参数传递给链中的下一个then;
  5. 当链用完thens 或者你抛出异常并且没有更多catches 时,promise 链结束;和
  6. then 和 catch 速度很快,但它们仍然是异步的,因此如果您并不真正需要它们,请不要将新元素添加到 Promise 链中。

【讨论】:

  • 你好安德鲁。感谢您详细描述如何构造此脚本的节点部分。但是,我真正的问题是我如何完成循环angular controller =&gt; angular service =&gt; node server route =&gt; node module =&gt; return success and read data or failure back up the chain 所以我可以例如在角度视图中显示读取的文本或处理 UI 中的错误。那是我真正苦苦挣扎的地方。
  • 好的。所以我假设你可以看到离开浏览器的请求和从服务器返回的有效响应。这是正确的吗?
  • 是的。例如,如果我登录节点模块,我可以打印出文件的内容
  • 如果您在 Chrome 中打开开发者工具并查看“网络”面板,当您单击按钮时,您是否看到离开浏览器的请求?
  • 我在 Angular 的回答中添加了更多内容,可能有用。
猜你喜欢
  • 1970-01-01
  • 2012-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-24
相关资源
最近更新 更多