[英]Node.js: How to run asynchronous code sequentially
我有这大块代码
User.find({}, function(err, users) {
for (var i = 0; i < users.length; i++) {
pseudocode
Friend.find({
'user': curUser._id
}, function(err, friends) * * ANOTHER CALLBACK * * {
for (var i = 0; i < friends.length; i++) {
pseudocode
}
console.log("HERE I'm CHECKING " + curUser);
if (curUser.websiteaccount != "None") {
request.post({
url: 'blah',
formData: blah
}, function(err, httpResponse, body) { * * ANOTHER CALLBACK * *
pseudocode
sendMail(friendResults, curUser);
});
} else {
pseudocode
sendMail(friendResults, curUser);
}
});
console.log("finished friend");
console.log(friendResults);
sleep.sleep(15);
console.log("finished waiting");
console.log(friendResults);
}
});
这里有几个异步的事情发生。 对于每个用户,我想找到他们相关的朋友并将他们连接到一个变量。 然后,我想检查该用户是否有网站帐户,如果有,请发帖请求并在那里获取一些信息。 唯一的问题是,由于代码没有等待回调完成,所有事情都发生了故障。 我一直在使用睡眠,但这并没有解决问题,因为它仍然是混乱的。
我已经研究过异步,但是这些函数是交织在一起而不是真正分开的,所以我不确定它是如何与异步一起工作的。
有什么建议让这段代码顺序运行?
谢谢!
由于其简单性,我更喜欢q https://www.npmjs.com/package/promise的promise模块
var Promises = require('promise');
var promise = new Promises(function (resolve, reject) {
// do some async stuff
if (success) {
resolve(data);
} else {
reject(reason);
}
});
promise.then(function (data) {
// function called when first promise returned
return new Promises(function (resolve, reject) {
// second async stuff
if (success) {
resolve(data);
} else {
reject(reason);
}
});
}, function (reason) {
// error handler
}).then(function (data) {
// second success handler
}, function (reason) {
// second error handler
}).then(function (data) {
// third success handler
}, function (reason) {
// third error handler
});
如你所见,你可以永远这样继续下去。 您也可以从异步处理程序返回简单值而不是promises,然后将这些值简单地传递给then
回调。
我重写了你的代码,所以它更容易阅读。 如果要保证同步执行,您可以选择做什么:
使用异步库。 它提供了一些帮助函数来运行你的代码,特别是,这个: https : //github.com/caolan/async#seriestasks-callback
使用promises可以避免进行回调,并简化代码API。 Promise是Javascript中的一项新功能,但在我看来,您可能不想立即执行此操作。 对于承诺仍然存在较差的库支持,并且不可能将它们与许多流行的库一起使用:(
现在 - 关于你的程序 - 你的代码实际上没有任何问题(假设你在pseucode块中没有异步代码)。 您的代码现在可以正常工作,并将按预期执行。
我建议目前使用async来满足您的顺序需求,因为它既适用于服务器端又适用于客户端,基本上可以保证与所有流行的库一起使用,并且使用/测试得很好。
清理下面的代码
User.find({}, function(err, users) {
for (var i = 0; i < users.length; i++) {
Friend.find({'user':curUser._id}, function(err, friends) {
for (var i = 0; i < friends.length; i++) {
// pseudocode
}
console.log("HERE I'm CHECKING " + curUser);
if (curUser.websiteaccount != "None") {
request.post({ url: 'blah', formData: 'blah' }, function(err, httpResponse, body) {
// pseudocode
sendMail(friendResults, curUser);
});
} else {
// pseudocode
sendMail(friendResults, curUser);
}
});
console.log("finished friend");
console.log(friendResults);
sleep.sleep(15);
console.log("finished waiting");
console.log(friendResults);
}
});
首先让我们更具功能性
var users = User.find({});
users.forEach(function (user) {
var friends = Friend.find({
user: user._id
});
friends.forEach(function (friend) {
if (user.websiteaccount !== 'None') {
post(friend, user);
}
sendMail(friend, user);
});
});
然后让我们异步
async.waterfall([
async.apply(Users.find, {}),
function (users, cb) {
async.each(users, function (user, cb) {
async.waterfall([
async.apply(Friends.find, { user, user.id}),
function (friends, cb) {
if (user.websiteAccount !== 'None') {
post(friend, user, function (err, data) {
if (err) {
cb(err);
} else {
sendMail(friend, user, cb);
}
});
} else {
sendMail(friend, user, cb);
}
}
], cb);
});
}
], function (err) {
if (err) {
// all the errors in one spot
throw err;
}
console.log('all done');
});
另外,这是你在进行连接,SQL非常擅长这些。
你会想要研究一些叫做承诺的东西。 它们允许您链接事件并按顺序运行它们。 这是一个很好的教程,介绍它们是什么以及如何使用它们http://strongloop.com/strongblog/promises-in-node-js-with-q-an-alternative-to-callbacks/
您还可以查看Async JavaScript库: Async它提供了用于在JavaScript中命令执行异步函数的实用程序函数。
注意:我认为您在处理程序中执行的查询数量是代码味道。 在查询级别可能更好地解决此问题。 那就说了,我们继续吧!
很难确切地知道你想要什么,因为你的伪代码可以使用清理恕我直言,但我要去你想做的是这样的:
你可以用很多不同的方式做到这一点 香草回调或异步工作很棒; 我将提倡承诺,因为它们是未来,图书馆的支持非常好。 我将使用rsvp ,因为它很轻,但任何Promise / A +兼容的库都可以解决问题。
// helpers to simulate async calls
var User = {}, Friend = {}, request = {};
var asyncTask = User.find = Friend.find = request.post = function (cb) {
setTimeout(function () {
var result = [1, 2, 3];
cb(null, result);
}, 10);
};
User.find(function (err, usersResults) {
// we reduce over the results, creating a "chain" of promises
// that we can .then off of
var userTask = usersResults.reduce(function (outerChain, outerResult) {
return outerChain.then(function (outerValue) {
// since we do not care about the return value or order
// of the asynchronous calls here, we just nest them
// and resolve our promise when they are done
return new RSVP.Promise(function (resolveFriend, reject){
Friend.find(function (err, friendResults) {
friendResults.forEach(function (result) {
request.post(function(err, finalResult) {
resolveFriend(outerValue + '\n finished user' + outerResult);
}, true);
});
});
});
});
}, RSVP.Promise.resolve(''));
// handle success
userTask.then(function (res) {
document.body.textContent = res;
});
// handle errors
userTask.catch(function (err) {
console.log(error);
});
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.