简体   繁体   English

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

[英]Iterate over the entries of a Map with an asynchronous callback function

I want to iterate the entries of a Map with an asynchronous callback function. The callback function should be started immediately for all elements.我想用异步回调 function 迭代Map的条目。应该立即为所有元素启动回调 function。

I ended up with the following code, which works but looks too complicated:我最终得到了以下代码,它可以工作但看起来太复杂了:

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);
  }
}

Is there an easier way to achieve this?有没有更简单的方法来实现这一目标?

According to MDN , Promise.all() takes an iterable of promises and waits for them to resolve. 根据 MDN , Promise.all() 接受一个可迭代的承诺并等待它们解决。 An iterable may be an array, as in your code, or a dedicated generator created by a generator function.一个可迭代对象可能是一个数组,就像在您的代码中一样,或者是由生成器 function 创建的专用生成器。 I don't know if this meets your definition of "easier", but here's one way to do it:我不知道这是否符合您对“更容易”的定义,但这是一种方法:

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));
}

You could do something shorter你可以做一些更短的事情

  • Array.from(map1.entries()) could be rewritten to [...map1] Array.from(map1.entries())可以重写为[...map1]
  • from what I see, doSomeOtherThing does not depend on doSomeThing so we could call them two concurrently据我所知, 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") })

All the bloat comes from the fact that there is no built in equivalent to Array.map() to map over Iterables.所有的臃肿都来自这样一个事实,即没有内置等效于Array.map()到 map over Iterables。

But you can write a little utility to do the job.但是您可以编写一个小实用程序来完成这项工作。

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);
    }
  ));
}

Personally, I would prefer to break the code using the simpler and readable for...of syntax with a few descriptive variables.就个人而言,我更喜欢使用更简单且可读for...of语法和一些描述性变量来破坏代码。 In such cases, "easier" is all about making the code less error-prone, easier to read and understand and above all, maintain in the long run.在这种情况下,“更容易”就是使代码更不容易出错,更容易阅读和理解,最重要的是,从长远来看,维护。

(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 );

}());  

The solution below uses iter-ops library:下面的解决方案使用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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM