我有一个在节点应用程序中运行的函数,由于我对如何正确编写异步代码缺乏了解而无法工作。下面是一个功能,它接收带有电子邮件的个人资料。我想遍历每封电子邮件并检查该用户是否存在于我的数据库中。如果他们这样做,我想返回给定的回调并完全存在该函数而不做任何其他事情。如果找不到用户,我会根据配置文件中给出的信息创建一个新用户,然后返回与新创建的用户相同的回调。截至目前,该功能按预期工作,但即使已在我的数据库中找到用户,它也会创建一个新用户。 ('User'变量在上面定义并具有'create'功能。另外,我想尽可能避免使用'async'节点模块。
function processProfile(profile, callback) {
var existingUser;
if (profile.emails) {
profile.emails.forEach(function(email) {
console.log("Searching for user with this email:" + email.value);
existingUser = findUserByEmail(email.value);
if (existingUser) {
console.log("Found the existing user");
return callback(null, existingUser);
}
});
if(!existingUser){
console.log("Creating new user");
var newUser = {
id: profile.id,
firstName: profile.name.givenName,
lastName: profile.name.familyName,
email: profile.emails[0].value
};
user.create(newUser, profile.provider, function(err, user) {
if (err) throw err;
return callback(null, user);
});
}
}
}
答案 0 :(得分:1)
这有什么问题吗?
function processProfile(profile, callback) {
var existingUser;
var index = 0;
function processNextEmail() {
if(index >= profile.emails.size()) return; //When we've popped nothing exit
var email = profile.emails[index++];
console.log("Searching for user with this email:" + email.value);
existingUser = findUserByEmail(email.value);
if (existingUser) {
console.log("Found the existing user");
callback(null, existingUser);
processEmail();//recursive call to prcess the next email
} else {
console.log("Creating new user");
var newUser = {
id: profile.id,
firstName: profile.name.givenName,
lastName: profile.name.familyName,
email: profile.emails[0].value
};
user.create(newUser, provider, function(err, user) {
if (err) throw err;
callback(null, user);
processNextEmail();//recursive call to process the next email after creating the user and adding it to the database.
});
}
}
processNextEmail();
}
如果您需要递归逻辑来不删除电子邮件,您可以在processProfile()闭包范围内进行涉及indice的简单修改。
另请注意,返回callback()行,并没有真正做任何事情。从异步发生的函数返回是浪费时间。只需调用回调,然后你可以调用一个空的返回来跳过函数的其余部分,如果你愿意,但它是不必要的,除非返回影响逻辑流。
编辑:事实证明这个例子太简单了,不太有趣。下面的代码我作为一些例子,用于工作中无法掌握异步代码的人。有一次我认为在节点中使用同步代码是可以的,用于收集配置数据。让我们假装我们将配置存储在一个文件中,然后从该文件中获取文件名,并从另一个文件中收集另一层配置数据。我们可以使用readFileSyn或使用readFile这两种方式。异步版本很棘手,因为我们需要等待第一步完成,因为我们必须从第一个文件中获取文件名,以便知道第二个文件的存储位置。以下是同步解决方案和异步解决方案的代码。
//The synchronous way
function useConfigurationData(configData) {
dosomethinginterestingwith(configData);
}
function getConfigurationData(fileName) {
var fileName2 = fs.readFileSync(fileName);
var configurationData = fs.readFileSync(fileName2);
return configurationData;
}
var fileData = getConfigurationData('someFile');
useConfigurationData(fileData);
//The equivalent async way
function getConfigurationData(fileName, useConfigDataCallBack) {
fs.readFile(fileName, getConfigDataStepTwo);
function getConfigDataStepTwo(err, fileName2) {
fs.readFile(fileName2, getConfigDataStepThree);
}
function getConfigDataStepThree(err, fileData) {
useConfigDataCallBack(fileData);
}
}
getConfigurationData('someFile', useConfigurationData);
请注意,我们提供给getConfigurationData的回调是最后一步。我们也可以只依赖于全局定义的getConfigurationData函数,但是作为回调传递它是更好的风格。
我喜欢这种语法,是第二个getConfigurationData函数的代码按顺序读取,非常同步。但是如果你遵循逻辑流程,它就会被运行为异步。它易于阅读并遵循节点异步I / O模型。在配置数据的情况下,我认为同步选项是可以接受的,但这仍然是如何从异步回调中获取同步行为和语法(ish)的一个很好的演示。