【问题标题】:make a async calls inside a for synchroniously在 for 中同步进行异步调用
【发布时间】:2015-03-25 00:39:00
【问题描述】:

我在使用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 以异步方式运行并且 DB 调用需要很长时间,因此输出如下所示:

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 链接),但我的问题是,它已经无法在循环中同步工作。有没有人对此有解决方案并可以解释一下?

编辑:apiNames 不是一个数组,它是一个包含一些数据的 JSON。以下是 apiNames 的示例:

[{
   "name": "James",
   "gender": "male"
},
{
   "name": "Betty",
   "gender": "female"
},
{
   "name": "Jon",
   "gender": "male"
}]

(添加了性别以在 json 中有更多信息。它对解决方案并不重要)

【问题讨论】:

  • apiNames 一个数组
  • 所以apiNames 是一个字符串?
  • 你能分享apiNames的样本吗,结构......还有浏览器兼容性需要什么
  • 我只是编辑了问题并分享了一个 apiNames 的示例。 JSON 要复杂得多。我只是缩短我的问题以保持示例清晰。

标签: javascript node.js asynchronous sails.js waterline


【解决方案1】:

由于 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

【讨论】:

  • 感谢您的示例。有什么办法可以保留循环而不是替换它?
  • @Depa 因为方法是异步的,AFAIK 除了使用基于回调的处理之外别无他法
  • 感谢伙伴,它似乎适用于这种特定情况!
【解决方案2】:

您可以使用递归来测试布尔值,您可以在准备好时进行切换。

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...");

这是未经测试的,我已经半睡半醒了...但我很确定这应该可以按您的意愿工作...或者至少让您接近:-)

【讨论】:

    【解决方案3】:

    因为我相信我们在这里谈论 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();
      });
    
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-12
      • 1970-01-01
      • 1970-01-01
      • 2017-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多