![](/img/trans.png)
[英]NodeJS NPM soap - how do I chain async methods without callbacks (ie use async or Promise)?
[英]Q Promise chain and NodeJS callbacks
我认为这是一个非常愚蠢的问题,但我很难兑现承诺。
我正在使用Q(用于nodejs)来同步几个异步函数。 这就像一个魅力。
var first = function () {
var d = Q.defer();
fs.readdir(path,function(err,files){
if(err) console.log(err);
d.resolve(files);
});
return d.promise;
};
var second = function (files) {
var list = new Array;
files.forEach(function(value, index){
var d = Q.defer();
console.log('looking for item in db', value);
db.query(
'SELECT * FROM test WHERE local_name =? ', [value],{
local_name : String,
},
function(rows) {
if (typeof rows !== 'undefined' && rows.length > 0){
console.log('found item!', rows[0].local_name);
d.resolve(rows[0]);
} else {
var itemRequest = value;
getItemData(itemRequest);
}
}
);
list.push(d.promise);
});
return Q.all(list);
};
first()
.then(second)
.done(function(list){
res.send(list);
});
我有这个小功能的问题:
getItemData(itemRequest)
此函数包含多个回调。 promise链在整个函数中运行得很好,但是忽略了我使用的所有回调(例如,我在函数中进行的几个XHR调用)。
该函数的简化版本如下所示(仅供参考):
function getItemData(itemRequest){
helper.xhrCall("call", function(response) {
var requestResponse = JSON.parse(response)
, requestInitialDetails = requestResponse.results[0];
downloadCache(requestInitialDetails,function(image) {
image = localImageDir+requestInitialDetails.image;
helper.xhrCall("call2", function(response) {
writeData(item,image,type, function(){
loadData(item);
});
});
} else {
writeData(item,image,type, function(){
loadData(item);
});
}
});
});
我使用的xhr函数如下所示:
xhrCall: function (url,callback) {
var request = require("request")
, colors = require('colors');
request({
url: url,
headers: {"Accept": "application/json"},
method: "GET"
}, function (error, response, body) {
if(!error){
callback(body);
}else{
console.log('Helper: XHR Error',error .red);
}
});
}
所以我的问题是:
再次,如果这是一个非常愚蠢的问题,对不起,但我不知道这里的正确做法是什么。
谢谢!
[编辑] Q.nfcall,我不明白
因此,我一直在研究Q.nfcall,它使我可以使用节点回调。 Bu我只是不完全了解它是如何工作的。 有人可以举一个简单的例子,说明如何将它用于具有多个异步xhr调用的函数吗?
我尝试过此方法,但是如您所见,我不太了解自己在做什么:
var second = Q.nfcall(second);
function second (files) {
[编辑2]
这是我的getitemdata函数回调链中的最后一个功能。 该函数与“ second”函数基本相同,但我直接推送结果,然后返回promise。 如上面所述,它可以工作,但是没有所有其他回调数据,因为它不等待回调返回任何数据。
function loadData(item) {
var d = Q.defer();
db.query(
'SELECT * FROM test WHERE local_name =? ', [item],{
local_name : String,
},
function(rows) {
if (typeof rows !== 'undefined' && rows.length > 0){
list.push(d.promise);
}
}
);
});
return Q.all(list);
};
第二次编辑后,您的答案还不清楚。
首先,在您的原始问题上,您的getItemData
对承诺链没有影响。
您可以更改函数的调用签名,并像这样传递您的延期承诺。
getItemData(itemRequest, d)
并将这个递延的承诺一直传递到您的xhrCall
并在那里解决。
我将重新编写您的整个实现,并确保所有函数都返回promise。
许多人将延迟的承诺视为反模式。 所以我使用和谐定义的Promise
API(下一个javascript)
说完之后,我将像这样重新实现您的原始代码(我尚未测试)
var Promise = Promise || require('es6-promise').Promise // a polyfill
;
function errHandler (err){
throw err
}
function makeQuery () {
var queryStr = 'SELECT * FROM test WHERE local_name =? '
, queryOpt = {local_name: String}
;
console.log('looking for item in db', value)
return new Promise(function(resolve, reject){
db.query(queryStr, [value], queryOpt, function(rows) {
if (typeof rows !== 'undefined' && rows.length > 0){
console.log('found item!', rows[0].local_name);
resolve(rows[0]);
} else {
// note that it returns a promise now.
getItemData(value).then(resolve).catch(errHandler)
}
})
})
}
function first () {
return new Promise(function(resolve, reject){
fs.readdir(path, function(err, files){
if (err) return reject(err)
resolve(files)
})
})
}
function second (files) {
return Promise.all(files.map(function(value){
return makeQuery(value)
});
}
first()
.then(second)
.then(res.send)
.catch(errHandler)
请注意, Promise
API上没有done
方法。
新的Promise
API的缺点之一是错误处理。 看看bluebird
。
它是一个健壮的Promise库,它与新的Promise API兼容并且具有许多Q
帮助器功能。
据我所知,您需要从getItemData
返回一个getItemData
。 像在second()
Q.defer()
一样使用Q.defer()
,并在回调完成数据后解析它。 然后,您可以将其推入list
。
若要保存代码,可以使用Q.nfcall立即调用节点样式回调函数,并返回一个Promise。 请参阅API文档中的示例: https : //github.com/kriskowal/q/wiki/API-Reference#qnfcallfunc-args
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.