使用异步回调函数迭代Map的条目

3
我想迭代一个Map的条目,并使用异步回调函数。该回调函数应立即为所有元素启动。
我最终得到了以下代码,它可以工作但看起来太复杂:
async function test() {
  const map1 = new Map();

  map1.set('a', 1);
  map1.set('b', 2);
  map1.set('c', 3);

  await Promise.all(Array.from(map1.entries()).map(async([
    key,
    value
  ]) => {
    await doSomeThing(key, value);
    await doSomeOtherThing(key, value);
  }
}

有更简单的方法实现这个吗?


await Promise.all(... 可以在没有 async 的情况下工作吗? - zer00ne
5个回答

1
根据MDN的说明,Promise.all()接收一个Promise可迭代对象并等待它们被解决。可迭代对象可以是数组(如您的代码中所示),也可以是由生成器函数创建的专用生成器。我不知道这是否符合您对“更容易”的定义,但以下是一种实现方式:
function* processMap(map, callback) {
    for (const entry of map.entries())
        yield callback(entry);
}

async function test() {
    const map = new Map();
    map.set("a", 1);
    map.set("b", 2);
    map.set("c", 3);
    
    const processEntry = async (entry) => {
        await doSomeThing(entry);
        await doSomeOtherThing(entry);
    };
    
    await Promise.all(processMap(map, processEntry));
}

1

您可以做一些更短的事情

  • Array.from(map1.entries()) 可以改写为 [...map1]
  • 从我看到的情况来看,doSomeOtherThing 不依赖于 doSomeThing,因此我们可以同时调用它们两个
await Promise.all(
  [...map1].flatMap(([key, val]) => [
    doSomeThing(key, val),
    doSomeOtherThing(key, val),
  ])
)

const doSomeThing = (key, val) =>
  new Promise(res => {
    console.log("doSomeThing start", key, val)
    setTimeout(() => {
      console.log("doSomeThing finish", key, val)
      res()
    }, 1000)
  })
const doSomeOtherThing = (key, val) =>
  new Promise(res => {
    console.log("doSomeOtherThing start", key, val)
    setTimeout(() => {
      console.log("doSomeOtherThing finish", key, val)
      res()
    }, 2000)
  })

async function test() {
  const map1 = new Map()

  map1.set("a", 1)
  map1.set("b", 2)
  map1.set("c", 3)

  /*
  await Promise.all(
    Array.from(map1.entries()).map(async ([key, value]) => {
      await doSomeThing(key, value)
      await doSomeOtherThing(key, value)
    })
  )
  */

  await Promise.all(
    [...map1].flatMap(([key, val]) => [
      doSomeThing(key, val),
      doSomeOtherThing(key, val),
    ])
  )
}

test().then(() => {
  console.log("done")
})


1

个人而言,我更喜欢使用更简单易读的for...of语法以及一些描述性变量来打破代码。在这种情况下,“更容易”意味着使代码更不容易出错,更易于阅读和理解,并且最重要的是,在长期维护中更易于管理。

(async function(){

  const map1 = new Map();
  
  map1.set('a', 1);
  map1.set('b', 2);
  map1.set('c', 3);

  const asyncOperations = [];
  
  for (const [key, value] of map1) {

    asyncOperations.push(async ()=>{
      await DoSomeThing(key, value);
      await DoSomeOtherThing(key, value);
    });
    
  }

  await Promise.all( asyncOperations );

}());  

0
所有的臃肿都来自于没有内置等价物 Array.map() 用于迭代映射。
但是您可以编写一个小型实用程序来完成工作。
function* map(iterable, mapper) {
  for (const item of iterable)
    yield mapper(item)
}

async function test() {
  const map1 = new Map();

  map1.set('a', 1);
  map1.set('b', 2);
  map1.set('c', 3);

  await Promise.all(map(
    map1,
    async ([key, value]) => {
      await doSomeThing(key, value);
      await doSomeOtherThing(key, value);
    }
  ));
}

0
以下解决方案使用 iter-ops 库:
import {pipe, toAsync, map, wait} from 'iter-ops';

const i = pipe(toAsync(map1), map(async ([key, value]) => {
    await doSomeThing(key, value);
    await doSomeOtherThing(key, value);
    return [key, value]; // or something else (result)
}), wait());

// trigger processing + print result:
for await(let res of i) {
    console.log(res);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接