调用异步函数时,通过数组同步循环

时间:2019-01-24 12:01:32

标签: javascript node.js

我的问题:我有一个包含用户和user_hash的数组,需要找到匹配的用户。我想出了以下解决方案:

//results is the array user objects
//safety_first.getUserHash is a function that calculates a user_hash, it retrieves the user-record based on the id and then combines values of some fields and a key and turns this into a hash.
if (results.length > 0)
    {
      var i = 0;
      function checkUserhash(user_id, user_hash, callback) {
        safety_first.getUserHash(user_id, function(check_user_hash) {
          if (user_hash == check_user_hash)
          {
            callback(user_id);
          }
          else
          {
            if ((i+1) < results.length)
            {
              i++;
              checkUserhash(results[i].id, user_hash, callback);
            }
            else
            {
              callback(false);
            }
          }
        });
      }

      checkUserhash(results[i].id, user_hash, function(user_id) {
        if (user_id)
        {
          console.log("MATCH: "+user_id);
        }
        else
        {
          console.log("NO MATCH");
        }
      });


    }

我首先尝试在for循环中执行此操作,但导致它异步调用checkUserhash,当找到匹配项时我无法中断循环。

我正在寻找其他可能的解决方案,请分享您的想法。

问候,彼得

1 个答案:

答案 0 :(得分:2)

您可以map在用户数组上创建一个promise数组。使用Promise.all等待这些承诺解决,然后遍历响应以检查哈希是否与ID相匹配。

在此示例中,我使用了async / await。我还模拟了一个哈希函数例程,以便您可以实际看到它。只需将解析度从'id'更改为'id + 1',然后重新运行演示程序即可看到Match变成No match

希望这是有用的。

const safety_first = {
  getUserHash(id) {
    return new Promise(resolve => {
      setTimeout(() => resolve(id), 1000);
    });
  }
}

async function checkUserHashes(userList, promises) {
  try {

    // await the promises to all resolve
    // `Promise.all` preserves the order...
    const res = await Promise.all(promises);

    // ...which makes it useful if you need to check the returned
    // results against the promise-producing array
    userList.forEach(({ id }, i) => {
      if (id === res[i]) console.log(`${id}|${res[i]} - Match`);
      if (id !== res[i]) console.log(`${id}|${res[i]} - No match`);
    });

  } catch (e) {
    console.log(e);
  }
};

const userList = [{ id: 1, userHash: 1 }, { id: 2, userHash: 2 }];

// `map` over the fields and return a
// validation promise for each
const promises = userList.map(({ id }) => {
  return safety_first.getUserHash(id);
});

// Pass in the original userList, and the generated promises
checkUserHashes(userList, promises);

更新:如果要在找到匹配项后跳出循环,那会容易一些:

const safety_first = {
  getUserHash(id) {
    return new Promise(resolve => {

      // This will match the second object (index 1)
      setTimeout(() => resolve(id === 1 ? id: id + 1), 1000);
    });
  }
}

async function checkUserHashes(userList) {

  // iterate over the array of objects
  for (let [index, obj] of userList.entries()) {

    // await for that one hash check
    const res = await safety_first.getUserHash(obj.id);

    // if it matches return the id
    if (obj.id === res) return obj;
  }

  // otherwise return null if there are no matches
  return null;
}

const userList = [{ id: 0, userHash: 1 }, { id: 1, userHash: 2 }];

(async () => {
  const id = await checkUserHashes(userList);
  console.log(id);
})();