异步等待在地图功能内无法正常工作

时间:2019-10-22 13:05:11

标签: javascript node.js ecmascript-6 promise async-await

我有一个像这样的数据集结构:

  _id: SomeMongoID,
  value: "a",
  counter: 1
}

因此,最初我的数据库表为空。 现在我有一个数组,其中值是这样的: const array = ["a", "a", "a"]

我想要的最初是我第一次进行搜索,因此它将清空结果,因此在这种情况下,插入查询,现在下一次获取条目,只需增加计数器即可。

为此,我编写了代码:

const testFunction = async(array) => {
  try {
    await Promise.all(
      array.map(async x => {
       const data = await CollectionName.findOne({value: x}).exec();
       // Every time data will return null
       if (data) {
         //In this case only counter will have to increase
         // But this block not run 
       } else {
         //So by this first value will store
         const value = new Value({
          value: x,
          counter: 1
         });
         await value.save()
       }
      })
    )
  } catch (error) {
    console.log(error)
  }
}
const array = ["a", "a", "a"]
testFunction(array);

问题是它将创建3个条目而不是单个条目。 map函数不会等待,我使用console.log()通过手动调试进行了检查。任何帮助或建议都非常感谢。

2 个答案:

答案 0 :(得分:0)

您不必在这里使用class someTable(tag: Tag) extends Table[(UUID, Array[String], Timestamp)](tag, “Some”) { def xyzId: Rep[UUID] = column[UUID]("xyz_id") **def abcId: Rep[Array[String]] = column[Array[String]](“abc_id", O.Length(500))** def createdTimestamp: Rep[Timestamp] = column[Timestamp]("created_timestamp") def * : ProvenShape[(UUID,Array[String], Option[UUID], String, Timestamp)] = (xyzId, abcId, createdTimestamp) } } 。您可以只使用map迭代来等待结果。

for ... of

说明:const testFunction = async(array) => { try { for (const x of array) { const data = await CollectionName.findOne({value: x}).exec(); // Every time data will return null if (data) { //In this case only counter will have to increase // But this block not run } else { //So by this first value will store const value = new Value({ value: x, counter: 1 }); await value.save() } } } catch (error) { console.log(error) } } const array = ["a", "a", "a"] testFunction(array); 不会等待,即使传递函数为map。而是收集您传递给它的函数的返回值。 async函数始终返回async。然后Promise等待着所有人。但是遍历数据不会等待任何事情。评估第一个Promise.all关键字的右侧后,它将立即返回promise。但是await起作用是因为它不使用回调函数。相反,它会评估每个循环并正确等待您要执行的操作。这样执行就非常接近了,好像里面的所有代码都是同步的一样。

答案 1 :(得分:0)

要节省时间并并行加载数据,请先处理我们自己的值。我们创建一个数据结构,该数据结构甚至在单次调用数据库之前就已经计数了相同的值。然后,我们仅在数据库中为数据结构中的唯一键调用数据库。这样可以将示例中的调用次数从3个减少到1个。在我的示例中,我向测试数据添加了两个"b"值。因此,通话次数将是2而不是5。

然后在数据库中查询唯一键。如果找到条目,则计数器将在测试数组内增加value次出现的次数。如果未找到,则会创建一个新条目,并将计数器设置为找到的出现次数。

const testFunction = async (array) => {
  try {

    // Create a statistics by counting each value fist
    // Creates a structure like { a: 3, b: 2}
    const countsByValues = array.reduce((acc, value) => {
      const newCount = acc[value] ? acc[value] + 1 : 1;
      return {
        ...acc,
        value: newCount
      };
    }, {});

    await Promise.all(
      // Use object entries to get array of [["a", 3], ["b", 2]]
      Object.entries(countsByValues).map(async ([x, count]) => {
       const data = await CollectionName.findOne({value: x}).exec();
       if (data) {
         //In this case only counter will have to increase by the count
         data.counter += count;
         //save data - insert your code saving code here
         await data.save();
       } else {
         //So by this first value will store
         const value = new Value({
          value: x,
          // new values will be the total count
          counter: count
         });
         await value.save()
       }
      })
    )
  } catch (error) {
    console.log(error)
  }
}
const array = ["a", "a", "b", "b", "a"]
testFunction(array);