来自php背景,我试图了解这个回调的东西。
基本上我想获得一些行,然后我想循环遍历这些行并检查它们与另一个模型(不同的数据库)。我希望电话回来等待它们全部通过并检查。
在sequelize循环遍历所有结果之前调用回调。
基本上我希望这个功能是'阻塞'。我需要改变什么?
toexport.getlasttransactions = function(lower,upper,callback){
var deferred = Q.defer();
var transactionsToUpdate = [];
///////////////////////////
// set import conditions //
///////////////////////////
var lowerbound = (lower) ? lower.format() : moment.utc().subtract(10, 'minutes').format();
var upperbound = (upper) ? upper.format() : moment.utc().format();
///////////////////////////////
// get IDs From Failed syncs //
///////////////////////////////
FailedSync.find({ limit: 100 })
.then(function(res){
var FailedIDs = [];
_.each(res, function(value,index){
FailedIDs.push(value.transaction_id);
});
// build condition
var queryCondition = { where: { updated_at: { between: [lowerbound,upperbound] } }, limit: 3 };
if(FailedIDs.length > 0){
queryCondition = {
where: Sequelize.and({ updated_at: { between: [lowerbound,upperbound] } },
Sequelize.or(
{ id: FailedIDs }
))
}
}
//////////////////////////////
// get Phoenix Transactions //
//////////////////////////////
PhoenixTransaction
.findAll(queryCondition)
.then(function(poenixTrx){
_.each(poenixTrx, function(value, index){
Transaction.findOne({ where: { id: value.id }})
.then(function(result){
if(!result || result.length === 0){
transactionsToUpdate.push(value);
console.log('!result || result.length === 0')
}
else if(result && result.length === 1){
if(result.hash != value.hash){
transactionsToUpdate.push(value);
console.log('result.hash != poenixTrx[i].hash')
}
}
})
.catch(function(err) {
console.log(err)
})
})
deferred.resolve(transactionsToUpdate);
})
.catch(function(err){
throw new Error("Something went wrong getting PhoenixTransaction")
})
})
deferred.promise.nodeify(callback);
return deferred.promise;
}
答案 0 :(得分:3)
您的代码中有许多新承诺用户拥有的模式:
承诺代表值随着时间的推移。您可以在以后通过then
使用promises并访问其结果,而不仅仅是立即 - Sequelize的承诺基于bluebird并提供丰富的API,为您进行聚合。
这是清理代码的注释版本 - 注意它不是嵌套:
toexport.getlasttransactions = function(lower,upper){ // no need for callback
var lowerbound = (lower || moment.utc().subtract(10, 'minutes')).format();
var upperbound = (upper || moment.utc()).format();
// use `map` over a `each` with a push.
var failedIds = FailedSync.find({ limit: 100 }).map(function(value){
return value.transaction_id;
});
// build condition.
var queryCondition = {
where: { updated_at: { between: [lowerbound,upperbound] } }, limit: 3
};
var query = failedIds.then(function(ids){ // use promise as proxy
if(ids.length === 0) return queryCondition;
return { // You can return a value or a promise from `then`
where: Sequelize.and({ updated_at: { between: [lowerbound,upperbound] } },
Sequelize.or({ id: ids});
};
});
var pheonixTransactions = query.then(function(condition){
return PhoenixTransaction.findAll(queryCondition); // filter based on result
});
return pheonixTransactions.map(function(value){ // again, map over each
return Transaction.findOne({ where: { id: value.id }}); // get the relevant one
}).filter(function(result){ // filter over if chain and push
return (!result || result.length === 0) ||
((result && result.length === 1) && result.hash != value.hash);
});
};
答案 1 :(得分:0)
理想情况下,您希望使用一系列承诺来使用Bluebird&reduce减少的内容,但我会提供async.series实现,因为它更容易理解。
安装异步
npm install async
在文件中要求
var async = require('async')
然后实现它:
//////////////////////////////
// get Phoenix Transactions //
//////////////////////////////
PhoenixTransaction
.findAll(queryCondition)
.then(function(poenixTrx){
var queryArray = poenixTrx.map(function(value){
return function(callback){
Transaction.findOne({ where: { id: value.id }})
.then(function(result){
if(!result || result.length === 0){
transactionsToUpdate.push(value);
console.log('!result || result.length === 0')
}
else if(result && result.length === 1){
if(result.hash != value.hash){
transactionsToUpdate.push(value);
console.log('result.hash != poenixTrx[i].hash')
}
}
// trigger callback with any result you want
callback(null, result)
})
.catch(function(err) {
console.log(err)
// trigger error callback
callback(err)
})
}
})
// async.series will loop through he queryArray, and execute each function one by one until they are all completed or an error is thrown.
// for additional information see https://github.com/caolan/async#seriestasks-callback
async.series(queryArray, function(err, callback){
// after all your queries are done, execution will be here
// resolve the promise with the transactionToUpdate array
deferred.resolve(transactionsToUpdate);
})
})
.catch(function(err){
throw new Error("Something went wrong getting PhoenixTransaction")
})
答案 2 :(得分:0)
说实话,整件事情有点混乱。特别是承诺/回调混乱可能会在某些时候引起你的问题。无论如何,你在transactionsToUpdate上使用deferred.resolve,它只是一个数组,所以它立即调用回调。
如果您保留该脚本,而不是使用_.each async(https://github.com/caolan/async)来运行您在paralell中的事务并将其用作回调。
看起来像这样:
toexport.getlasttransactions = function(lower,upper,callback){
var transactionsToUpdate = [];
///////////////////////////
// set import conditions //
///////////////////////////
var lowerbound = (lower) ? lower.format() : moment.utc().subtract(10, 'minutes').format();
var upperbound = (upper) ? upper.format() : moment.utc().format();
///////////////////////////////
// get IDs From Failed syncs //
///////////////////////////////
FailedSync.find({ limit: 100 })
.then(function(res){
var FailedIDs = [];
_.each(res, function(value,index){
FailedIDs.push(value.transaction_id);
});
// build condition
var queryCondition = { where: { updated_at: { between: [lowerbound,upperbound] } }, limit: 3 };
if(FailedIDs.length > 0){
queryCondition = {
where: Sequelize.and({ updated_at: { between: [lowerbound,upperbound] } },
Sequelize.or(
{ id: FailedIDs }
))
}
}
//////////////////////////////
// get Phoenix Transactions //
//////////////////////////////
PhoenixTransaction
.findAll(queryCondition)
.then(function(poenixTrx){
async.each(poenixTrx, function(value, next){
Transaction.findOne({ where: { id: value.id }})
.then(function(result){
if(!result || result.length === 0){
transactionsToUpdate.push(value);
console.log('!result || result.length === 0')
}
else if(result && result.length === 1){
if(result.hash != value.hash){
transactionsToUpdate.push(value);
console.log('result.hash != poenixTrx[i].hash')
}
}
next();
})
.catch(function(err) {
console.log(err)
})
}, function(err) {
//Return the array transactionsToUpdate in your callback for further use
return callback(err, transactionsToUpdate);
});
})
.catch(function(err){
throw new Error("Something went wrong getting PhoenixTransaction")
})
})
}
这将是回调的方式。 但是你需要根据自己想要使用的内容进行思考:回调或承诺。不要同时使用它们(如:如果你的方法需要回调,它不应该返回一个promise,或者如果它返回一个promise它不应该期望一个回调)。
如果你使用回调你不想抛出错误,你只需要调用回调并在回调中给出错误 - 使用你的方法的任何人都可以检查回调中的错误并处理它。
希望你有点意义,我知道整个回调和承诺事情有点奇怪,如果你来自像php这样的东西,它需要一些习惯:)
答案 3 :(得分:0)
感谢您解释这些差异。我认为使用promises是前进的方向,因为它使代码看起来更好并且避免了这个"回调地狱"。
例如:
PhoenixSyncTransactions.getlasttransactions(lastTimeSynced,null)
.then(function(res){
return PersistTransaction.prepareTransactions(res).then(function(preparedTrx){
return preparedTrx;
})
}).then(function(preparedTrx){
return PersistTransaction.persistToDB(preparedTrx).then(function(Processes){
return Processes;
})
})
.then(function(Processes){
return PersistTransaction.checkIfMultiProcess(Processes).then(function(result){
return result;
})
})
.then(function(result){
console.log('All jobs done');
})
整个代码更容易阅读。