在 for 中同步进行异步调用
make a async calls inside a for synchroniously
我在处理 sails.js 中的异步事件时遇到了一些问题。
我正在从 JSONapi 获取一些数据,并尝试在 for 循环内将它们写入我的数据库。一切都需要一个接一个地执行(以正确的顺序)。为了使示例简单,我们只说我正在尝试执行以下操作:
//let apiNames be a JSON that contains some names in that order: James, Betty, Jon
//let Customer be a DB which contains that names and related age
for(index in apiNames){
console.log("Searching for "+apiNames[index].name+" in the Database...);
Customer.find({name:apiNames[index].name}).exec(function(err,customerData){
console.log("Found "+apiNames[index].name+" in the Database!");
console.log(customerData);
});
}
建议日志应如下所示:
Searching for James in the Database....
Found James in Database!
{name:James, age:23}
Searching for Betty in the Database....
Found Betty in Database!
{name:Betty, age:43}
Searching for Jon in the Database....
Found Jon in Database!
{name:Jon, age:36}
由于 Javascript 是 运行 异步并且数据库调用花费了很长时间,所以输出看起来像这样:
Searching for James in the Database....
Searching for Betty in the Database....
Searching for Jon in the Database....
Found James in Database!
{name:James, age:23}
Found Betty in Database!
{name:Betty, age:43}
Found Jon in Database!
{name:Jon, age:36}
我已经尝试了几种方法来强制循环同步工作,但没有任何效果。 AFAIK 如果我在 exec 中调用某些东西,它应该 运行 同步(通过将它与另一个 exec 链接),但我的问题是,它已经在循环中同步工作失败。有没有人对此有解决方案并可以解释一下?
Edit: apiNames 不是数组,它是一个 JSON,里面有一些数据。这是 apiNames 的示例:
[{
"name": "James",
"gender": "male"
},
{
"name": "Betty",
"gender": "female"
},
{
"name": "Jon",
"gender": "male"
}]
(在 json 中添加了性别以获得更多信息。这对解决方案并不重要)
由于 apiNames 是一个对象,为了与 IE9+ 兼容,我们可以使用 Object.keys() 来获取对象中的键名称并使用它来迭代 apiNames
//process all names in the array one by one
function process(apiNames, keys) {
//if there are no items in the array return from the function
if (!keys.length) {
return;
}
//get the first name in the array
var key = keys.shift();
var name = apiNames[key];
console.log("Searching for " + name + " in the Database...");
Customer.find({
name: name
}).exec(function (err, customerData) {
console.log("Found " + name + " in the Database!");
console.log(customerData);
//once the current item is processed call the next process method so that the second item can be processed
process(apiNames, keys);
});
}
//call the process method with an array
var keys = Object.keys(apiNames);
process(apiNames, keys);
对于旧版浏览器,使用 polyfill 添加对 Object.keys() 的支持,例如 one provided by MDN
演示:Fiddle
您可以使用递归来测试布尔值,您可以在准备好后进行切换。
var isFinding = false;
var found = [];
for (index in apiNames) {
checkIndex(index);
}
function checkIndex (index) {
if (index) {
found[index - 1]
? findCustomer(index)
: setTimeout(checkIndex, 100, index);
} else {
findCustomer(index);
}
}
function findCustomer (index) {
if (isFinding) {
setTimeout(findCustomer, 100, index)
} else {
isFinding = true;
console.log("Searching for "+apiNames[index]+" in the Database...");
Customer.find({name:apiNames[index]}).exec(function(err,customerData){
console.log("Found "+apiNames[index]+" in the Database!");
console.log(customerData);
found[index] = true;
isFinding = false;
});
}
}
console.log("Searching for "+apiNames[index]+" in the Database...");
这是未经测试的,我半睡半醒...但我很确定这应该可以按照您想要的方式工作...或者至少让您接近 :-)
因为我相信我们在这里谈论 nodejs,所以我会使用 async.js
并且 apiNames 对我来说看起来像数组,如果不是,那就创建它
var async = require('async');
var apiNames = JSON.parse('[{"name": "James","gender": "male"},{"name": "Betty","gender": "female"}]');
async.eachSeries(apiNames, function(apiName, callback) {
console.log("Searching for "+apiName.name+" in the Database...);
Customer.find({name:apiName.name}).exec(function(err,customerData){
console.log("Found "+apiName.name+" in the Database!");
console.log(customerData);
callback();
});
});
我在处理 sails.js 中的异步事件时遇到了一些问题。
我正在从 JSONapi 获取一些数据,并尝试在 for 循环内将它们写入我的数据库。一切都需要一个接一个地执行(以正确的顺序)。为了使示例简单,我们只说我正在尝试执行以下操作:
//let apiNames be a JSON that contains some names in that order: James, Betty, Jon
//let Customer be a DB which contains that names and related age
for(index in apiNames){
console.log("Searching for "+apiNames[index].name+" in the Database...);
Customer.find({name:apiNames[index].name}).exec(function(err,customerData){
console.log("Found "+apiNames[index].name+" in the Database!");
console.log(customerData);
});
}
建议日志应如下所示:
Searching for James in the Database....
Found James in Database!
{name:James, age:23}
Searching for Betty in the Database....
Found Betty in Database!
{name:Betty, age:43}
Searching for Jon in the Database....
Found Jon in Database!
{name:Jon, age:36}
由于 Javascript 是 运行 异步并且数据库调用花费了很长时间,所以输出看起来像这样:
Searching for James in the Database....
Searching for Betty in the Database....
Searching for Jon in the Database....
Found James in Database!
{name:James, age:23}
Found Betty in Database!
{name:Betty, age:43}
Found Jon in Database!
{name:Jon, age:36}
我已经尝试了几种方法来强制循环同步工作,但没有任何效果。 AFAIK 如果我在 exec 中调用某些东西,它应该 运行 同步(通过将它与另一个 exec 链接),但我的问题是,它已经在循环中同步工作失败。有没有人对此有解决方案并可以解释一下?
Edit: apiNames 不是数组,它是一个 JSON,里面有一些数据。这是 apiNames 的示例:
[{
"name": "James",
"gender": "male"
},
{
"name": "Betty",
"gender": "female"
},
{
"name": "Jon",
"gender": "male"
}]
(在 json 中添加了性别以获得更多信息。这对解决方案并不重要)
由于 apiNames 是一个对象,为了与 IE9+ 兼容,我们可以使用 Object.keys() 来获取对象中的键名称并使用它来迭代 apiNames
//process all names in the array one by one
function process(apiNames, keys) {
//if there are no items in the array return from the function
if (!keys.length) {
return;
}
//get the first name in the array
var key = keys.shift();
var name = apiNames[key];
console.log("Searching for " + name + " in the Database...");
Customer.find({
name: name
}).exec(function (err, customerData) {
console.log("Found " + name + " in the Database!");
console.log(customerData);
//once the current item is processed call the next process method so that the second item can be processed
process(apiNames, keys);
});
}
//call the process method with an array
var keys = Object.keys(apiNames);
process(apiNames, keys);
对于旧版浏览器,使用 polyfill 添加对 Object.keys() 的支持,例如 one provided by MDN
演示:Fiddle
您可以使用递归来测试布尔值,您可以在准备好后进行切换。
var isFinding = false;
var found = [];
for (index in apiNames) {
checkIndex(index);
}
function checkIndex (index) {
if (index) {
found[index - 1]
? findCustomer(index)
: setTimeout(checkIndex, 100, index);
} else {
findCustomer(index);
}
}
function findCustomer (index) {
if (isFinding) {
setTimeout(findCustomer, 100, index)
} else {
isFinding = true;
console.log("Searching for "+apiNames[index]+" in the Database...");
Customer.find({name:apiNames[index]}).exec(function(err,customerData){
console.log("Found "+apiNames[index]+" in the Database!");
console.log(customerData);
found[index] = true;
isFinding = false;
});
}
}
console.log("Searching for "+apiNames[index]+" in the Database...");
这是未经测试的,我半睡半醒...但我很确定这应该可以按照您想要的方式工作...或者至少让您接近 :-)
因为我相信我们在这里谈论 nodejs,所以我会使用 async.js
并且 apiNames 对我来说看起来像数组,如果不是,那就创建它
var async = require('async');
var apiNames = JSON.parse('[{"name": "James","gender": "male"},{"name": "Betty","gender": "female"}]');
async.eachSeries(apiNames, function(apiName, callback) {
console.log("Searching for "+apiName.name+" in the Database...);
Customer.find({name:apiName.name}).exec(function(err,customerData){
console.log("Found "+apiName.name+" in the Database!");
console.log(customerData);
callback();
});
});