我正在尝试使用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
部分组织起来。
答案 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()最终将解析整个响应对象而不是响应数据。
要记住的是,你可以(而且绝对应该)尽可能地回收你的承诺。基本上,你需要知道的所有承诺是:
then
和catch
方法,您可以将逻辑包装在其中; then
和catch
都会作为新承诺返回; then
或catch
内引发异常,您将被直接转到下一个catch
,如果有的话; then
或catch
返回一个值,它将作为参数传递给链中的下一个then
; then
或者您抛出异常并且不再有catch
es时,承诺链结束;和then
和catch
速度很快,但它们仍然是异步的,因此如果您真的不需要,请不要将新元素添加到承诺链中。