p-mapで配列の配列の非同期処理

配列の配列の非同期処理のやり方のメモ

# p-map

https://www.npmjs.com/package/p-map

## 配列が１つの場合

### 全部同時実行

```plantuml
@startuml
robust "全体" as all
concise "https://test/1" as test1
concise "https://test/2" as test2
concise "https://test/3" as test3
concise "https://test/4" as test4
concise "https://test/5" as test5

@all
0 is 待機中
+1 is 処理中
+5 is 待機中

@test1
1 is 処理中
+1 is {hidden}

@test2
1 is 処理中
+2 is {hidden}

@test3
1 is 処理中
+3 is {hidden}

@test4
1 is 処理中
+4 is {hidden}

@test5
1 is 処理中
+5 is {hidden}

@enduml
```

```ts
import { describe, test } from 'vitest'
import pMap from 'p-map'

const sleep = (wait: number) =>
  new Promise((resolve) => {
    setTimeout(() => resolve(wait), wait)
  })

function checkLog(text: string) {
  console.log(`time : ${new Date().toISOString()} - text: ${text}`)
}

const testOptions = {
  timeout: 1000 * 100
}

const mapper1 = async (site: string) => {
  const index = site.slice(-1)
  const wait = Number(index) * 1000
  const _wait = await sleep(wait)
  checkLog(site)
  return `${site} - ${_wait}`
}

describe('p-map 非同期処理１つの配列', () => {
  test('使い方１ー全部同時実行', testOptions, async () => {
    const sites = [
      'https://test/1',
      'https://test/2',
      'https://test/3',
      'https://test/4',
      'https://test/5'
    ]

    checkLog('[start]')

    const result = await pMap(sites, mapper1)

    console.log(result)
  })
})
```

実行結果
```ts
time : 2025-01-18T04:05:48.913Z - text: [start]
time : 2025-01-18T04:05:49.926Z - text: https://test/1
time : 2025-01-18T04:05:50.926Z - text: https://test/2
time : 2025-01-18T04:05:51.926Z - text: https://test/3
time : 2025-01-18T04:05:52.915Z - text: https://test/4
time : 2025-01-18T04:05:53.926Z - text: https://test/5
[
  'https://test/1 - 1000',
  'https://test/2 - 2000',
  'https://test/3 - 3000',
  'https://test/4 - 4000',
  'https://test/5 - 5000'
]
```


### 最大２個まで同時実行

```plantuml
@startuml
robust "全体" as all
concise "https://test/1" as test1
concise "https://test/2" as test2
concise "https://test/3" as test3
concise "https://test/4" as test4
concise "https://test/5" as test5

@all
0 is 待機中
+1 is 処理中
+9 is 待機中

@test1
1 is 処理中
+1 is {hidden}

@test2
1 is 処理中
+2 is {hidden}

@test3
2 is 処理中
+3 is {hidden}

@test4
3 is 処理中
+4 is {hidden}

@test5
5 is 処理中
+5 is {hidden}

@enduml
```

```ts
import { describe, test } from 'vitest'
import pMap from 'p-map'

const sleep = (wait: number) =>
  new Promise((resolve) => {
    setTimeout(() => resolve(wait), wait)
  })

function checkLog(text: string) {
  console.log(`time : ${new Date().toISOString()} - text: ${text}`)
}

const testOptions = {
  timeout: 1000 * 100
}

const mapper1 = async (site: string) => {
  const index = site.slice(-1)
  const wait = Number(index) * 1000
  const _wait = await sleep(wait)
  checkLog(site)
  return `${site} - ${_wait}`
}

describe('p-map 非同期処理１つの配列', () => {
  test('使い方２ー最大２個まで同時実行', testOptions, async () => {
    const sites = [
      'https://test/1',
      'https://test/2',
      'https://test/3',
      'https://test/4',
      'https://test/5'
    ]

    const concurrency = 2

    checkLog('[start]')

    const result = await pMap(sites, mapper1, { concurrency })

    console.log(result)
  })
})
```

実行結果
```ts
time : 2025-01-18T04:20:21.202Z - text: [start]
time : 2025-01-18T04:20:22.207Z - text: https://test/1
time : 2025-01-18T04:20:23.208Z - text: https://test/2
time : 2025-01-18T04:20:25.210Z - text: https://test/3
time : 2025-01-18T04:20:27.210Z - text: https://test/4
time : 2025-01-18T04:20:30.212Z - text: https://test/5
[
  'https://test/1 - 1000',
  'https://test/2 - 2000',
  'https://test/3 - 3000',
  'https://test/4 - 4000',
  'https://test/5 - 5000'
]
```


## 配列が２つの場合（シンプル）

### 全部同時実行からの全部同時実行

```plantuml
@startuml
robust "全体" as all
concise "https://test/3" as test3
concise "https://test/3/1" as test3_1
concise "https://test/3/2" as test3_2
concise "https://test/3/3" as test3_3

@all
0 is 待機中
+1 is 処理中
+6 is 待機中

@test3
1 is 処理中
+3 is {hidden}

@test3_1
4 is 処理中
+1 is {hidden}

@test3_2
4 is 処理中
+2 is {hidden}

@test3_3
4 is 処理中
+3 is {hidden}

@enduml
```

```ts
import { describe, test } from 'vitest'
import pMap from 'p-map'

const sleep = (wait: number) =>
  new Promise((resolve) => {
    setTimeout(() => resolve(wait), wait)
  })

function checkLog(text: string) {
  console.log(`time : ${new Date().toISOString()} - text: ${text}`)
}

const testOptions = {
  timeout: 1000 * 100
}

const mapper1 = async (site: string) => {
  const index = site.slice(-1)
  const wait = Number(index) * 1000
  const _wait = await sleep(wait)
  checkLog(site)
  return `${site} - ${_wait}`
}
function getWaitFromMapper1Message(mapper1Message: string) {
  const mapper1WaitString = mapper1Message.substring(mapper1Message.indexOf('-') + 1)
  const mapper1Wait = Number(mapper1WaitString)
  return mapper1Wait
}

const mapper2_max = async (sites: string[]) => {
  const site = sites[0]
  const index = site.substring(site.length - 3, site.length - 2)
  const wait = Number(index) * 1000
  const _wait = (await sleep(wait)) as number
  checkLog(`mapper2-index = ${index}`)

  const result = await pMap(sites, mapper1)
  const waitResults = result.map(getWaitFromMapper1Message)
  const maxWait = Math.max(...waitResults)
  return `${site.substring(0, site.length - 2)} - ${_wait + maxWait}`
}

describe('p-map 非同期処理２つの配列', () => {
  test('使い方１ー全部同時実行からの全部同時実行', testOptions, async () => {
    const sites = [
      // ['https://test/1/1'],
      // ['https://test/2/1', 'https://test/2/2']
      ['https://test/3/1', 'https://test/3/2', 'https://test/3/3']
      // ['https://test/4/1', 'https://test/4/2', 'https://test/4/3', 'https://test/4/4'],
      // [
      //   'https://test/5/1',
      //   'https://test/5/2',
      //   'https://test/5/3',
      //   'https://test/5/4',
      //   'https://test/5/5'
      // ]
    ]

    checkLog('[start]')

    const result = await pMap(sites, mapper2_max)

    console.log(result)
  })
})
```

実行結果
```ts
time : 2025-01-18T04:26:18.753Z - text: [start]
time : 2025-01-18T04:26:21.755Z - text: mapper2-index = 3
time : 2025-01-18T04:26:22.770Z - text: https://test/3/1
time : 2025-01-18T04:26:23.772Z - text: https://test/3/2
time : 2025-01-18T04:26:24.756Z - text: https://test/3/3
[ 'https://test/3 - 6000' ]
```


### 全部同時実行からの直列実行

```plantuml
@startuml
robust "全体" as all
concise "https://test/3" as test3
concise "https://test/3/1" as test3_1
concise "https://test/3/2" as test3_2
concise "https://test/3/3" as test3_3

@all
0 is 待機中
+1 is 処理中
+9 is 待機中

@test3
1 is 処理中
+3 is {hidden}

@test3_1
4 is 処理中
+1 is {hidden}

@test3_2
5 is 処理中
+2 is {hidden}

@test3_3
7 is 処理中
+3 is {hidden}

@enduml
```

```ts
import { describe, test } from 'vitest'
import pMap from 'p-map'

const sleep = (wait: number) =>
  new Promise((resolve) => {
    setTimeout(() => resolve(wait), wait)
  })

function checkLog(text: string) {
  console.log(`time : ${new Date().toISOString()} - text: ${text}`)
}

const testOptions = {
  timeout: 1000 * 100
}

function sum(a: number, b: number) {
  return a + b
}

const mapper1 = async (site: string) => {
  const index = site.slice(-1)
  const wait = Number(index) * 1000
  const _wait = await sleep(wait)
  checkLog(site)
  return `${site} - ${_wait}`
}
function getWaitFromMapper1Message(mapper1Message: string) {
  const mapper1WaitString = mapper1Message.substring(mapper1Message.indexOf('-') + 1)
  const mapper1Wait = Number(mapper1WaitString)
  return mapper1Wait
}

const mapper2_sum = async (sites: string[]) => {
  const site = sites[0]
  const index = site.substring(site.length - 3, site.length - 2)
  const wait = Number(index) * 1000
  const _wait = (await sleep(wait)) as number
  checkLog(`mapper2-index = ${index}`)

  const concurrency = 1
  const result = await pMap(sites, mapper1, { concurrency })
  const waitResults = result.map(getWaitFromMapper1Message)
  const sumWait = waitResults.reduce(sum, 0)
  return `${site.substring(0, site.length - 2)} - ${_wait + sumWait}`
}

describe('p-map 非同期処理２つの配列', () => {
  test('使い方３ー全部同時実行からの直列実行', testOptions, async () => {
    const sites = [
      // ['https://test/1/1'],
      // ['https://test/2/1', 'https://test/2/2']
      ['https://test/3/1', 'https://test/3/2', 'https://test/3/3']
      // ['https://test/4/1', 'https://test/4/2', 'https://test/4/3', 'https://test/4/4'],
      // [
      //   'https://test/5/1',
      //   'https://test/5/2',
      //   'https://test/5/3',
      //   'https://test/5/4',
      //   'https://test/5/5'
      // ]
    ]

    checkLog('[start]')

    const result = await pMap(sites, mapper2_sum)

    console.log(result)
  })
})
```

実行結果
```ts
time : 2025-01-18T04:30:41.568Z - text: [start]
time : 2025-01-18T04:30:44.582Z - text: mapper2-index = 3
time : 2025-01-18T04:30:45.583Z - text: https://test/3/1
time : 2025-01-18T04:30:47.586Z - text: https://test/3/2
time : 2025-01-18T04:30:50.602Z - text: https://test/3/3
[ 'https://test/3 - 9000' ]
```



### 全部同時実行からの最大２個まで同時実行

```plantuml
@startuml
robust "全体" as all
concise "https://test/3" as test3
concise "https://test/3/1" as test3_1
concise "https://test/3/2" as test3_2
concise "https://test/3/3" as test3_3

@all
0 is 待機中
+1 is 処理中
+7 is 待機中

@test3
1 is 処理中
+3 is {hidden}

@test3_1
4 is 処理中
+1 is {hidden}

@test3_2
4 is 処理中
+2 is {hidden}

@test3_3
5 is 処理中
+3 is {hidden}

@enduml
```

```ts
import { describe, test } from 'vitest'
import pMap from 'p-map'

const sleep = (wait: number) =>
  new Promise((resolve) => {
    setTimeout(() => resolve(wait), wait)
  })

function checkLog(text: string) {
  console.log(`time : ${new Date().toISOString()} - text: ${text}`)
}

const testOptions = {
  timeout: 1000 * 100
}

function array_slice_2(acc: number[][], cur: number) {
  const topLengt = acc.length
  if (topLengt == 0) {
    acc.push([cur])
  } else if (acc[topLengt - 1].length == 2) {
    acc.push([cur])
  } else {
    acc[topLengt - 1].push(cur)
  }

  return acc
}

function array_sum_slice_2(acc: number[], cur: number[]) {
  const accLengt = acc.length
  if (accLengt == 0) {
    acc.push(...cur)
  } else {
    const curLength = cur.length
    const min = Math.min(acc[0], acc[1])
    const minIndex = acc[0] == min ? 0 : 1
    acc[minIndex] += cur[0]

    if (curLength == 2) {
      const min2 = Math.min(acc[0], acc[1])
      const min2Index = acc[0] == min2 ? 0 : 1
      acc[min2Index] += cur[1]
    }
  }

  return acc
}

const mapper1 = async (site: string) => {
  const index = site.slice(-1)
  const wait = Number(index) * 1000
  const _wait = await sleep(wait)
  checkLog(site)
  return `${site} - ${_wait}`
}
function getWaitFromMapper1Message(mapper1Message: string) {
  const mapper1WaitString = mapper1Message.substring(mapper1Message.indexOf('-') + 1)
  const mapper1Wait = Number(mapper1WaitString)
  return mapper1Wait
}

const mapper2_limit2 = async (sites: string[]) => {
  const site = sites[0]
  const index = site.substring(site.length - 3, site.length - 2)
  const wait = Number(index) * 1000
  const _wait = (await sleep(wait)) as number
  checkLog(`mapper2-index = ${index}`)

  const concurrency = 2
  const result = await pMap(sites, mapper1, { concurrency })
  const waitResults = result.map(getWaitFromMapper1Message)
  const waitResultsArray = waitResults.reduce(array_slice_2, [])
  const waitResultsArraySum = waitResultsArray.reduce(array_sum_slice_2, [])
  const sumWait = Math.max(...waitResultsArraySum)
  return `${site.substring(0, site.length - 2)} - ${_wait + sumWait}`
}

describe('p-map 非同期処理２つの配列', () => {
  test('使い方５ー全部同時実行からの最大２個まで同時実行', testOptions, async () => {
    const sites = [
      // ['https://test/1/1'],
      // ['https://test/2/1', 'https://test/2/2']
      ['https://test/3/1', 'https://test/3/2', 'https://test/3/3']
      // ['https://test/4/1', 'https://test/4/2', 'https://test/4/3', 'https://test/4/4'],
      // [
      //   'https://test/5/1',
      //   'https://test/5/2',
      //   'https://test/5/3',
      //   'https://test/5/4',
      //   'https://test/5/5'
      // ]
    ]

    checkLog('[start]')

    const result = await pMap(sites, mapper2_limit2)

    console.log(result)
  })
})
```

実行結果
```ts
time : 2025-01-18T04:33:49.234Z - text: [start]
time : 2025-01-18T04:33:52.242Z - text: mapper2-index = 3
time : 2025-01-18T04:33:53.259Z - text: https://test/3/1
time : 2025-01-18T04:33:54.260Z - text: https://test/3/2
time : 2025-01-18T04:33:56.260Z - text: https://test/3/3
[ 'https://test/3 - 7000' ]
```


## 配列が２つの場合（複雑）

### 全部同時実行からの全部同時実行

```plantuml
@startuml
robust "全体" as all

concise "https://test/1" as test1
concise "https://test/1/1" as test1_1

concise "https://test/2" as test2
concise "https://test/2/1" as test2_1
concise "https://test/2/2" as test2_2

concise "https://test/3" as test3
concise "https://test/3/1" as test3_1
concise "https://test/3/2" as test3_2
concise "https://test/3/3" as test3_3

concise "https://test/4" as test4
concise "https://test/4/1" as test4_1
concise "https://test/4/2" as test4_2
concise "https://test/4/3" as test4_3
concise "https://test/4/4" as test4_4

concise "https://test/5" as test5
concise "https://test/5/1" as test5_1
concise "https://test/5/2" as test5_2
concise "https://test/5/3" as test5_3
concise "https://test/5/4" as test5_4
concise "https://test/5/5" as test5_5

@all
0 is 待機中
+1 is 処理中
+10 is 待機中

@test1
1 is 処理中
+1 is {hidden}
@test1_1
2 is 処理中
+1 is {hidden}

@test2
1 is 処理中
+2 is {hidden}
@test2_1
3 is 処理中
+1 is {hidden}
@test2_2
3 is 処理中
+2 is {hidden}

@test3
1 is 処理中
+3 is {hidden}
@test3_1
4 is 処理中
+1 is {hidden}
@test3_2
4 is 処理中
+2 is {hidden}
@test3_3
4 is 処理中
+3 is {hidden}

@test4
1 is 処理中
+4 is {hidden}
@test4_1
5 is 処理中
+1 is {hidden}
@test4_2
5 is 処理中
+2 is {hidden}
@test4_3
5 is 処理中
+3 is {hidden}
@test4_4
5 is 処理中
+4 is {hidden}

@test5
1 is 処理中
+5 is {hidden}
@test5_1
6 is 処理中
+1 is {hidden}
@test5_2
6 is 処理中
+2 is {hidden}
@test5_3
6 is 処理中
+3 is {hidden}
@test5_4
6 is 処理中
+4 is {hidden}
@test5_5
6 is 処理中
+5 is {hidden}

@enduml
```

```ts
import { describe, test } from 'vitest'
import pMap from 'p-map'

const sleep = (wait: number) =>
  new Promise((resolve) => {
    setTimeout(() => resolve(wait), wait)
  })

function checkLog(text: string) {
  console.log(`time : ${new Date().toISOString()} - text: ${text}`)
}

const testOptions = {
  timeout: 1000 * 100
}

const mapper1 = async (site: string) => {
  const index = site.slice(-1)
  const wait = Number(index) * 1000
  const _wait = await sleep(wait)
  checkLog(site)
  return `${site} - ${_wait}`
}
function getWaitFromMapper1Message(mapper1Message: string) {
  const mapper1WaitString = mapper1Message.substring(mapper1Message.indexOf('-') + 1)
  const mapper1Wait = Number(mapper1WaitString)
  return mapper1Wait
}

const mapper2_max = async (sites: string[]) => {
  const site = sites[0]
  const index = site.substring(site.length - 3, site.length - 2)
  const wait = Number(index) * 1000
  const _wait = (await sleep(wait)) as number
  checkLog(`mapper2-index = ${index}`)

  const result = await pMap(sites, mapper1)
  const waitResults = result.map(getWaitFromMapper1Message)
  const maxWait = Math.max(...waitResults)
  return `${site.substring(0, site.length - 2)} - ${_wait + maxWait}`
}

describe('p-map 非同期処理２つの配列', () => {
  test('使い方２ー全部同時実行からの全部同時実行', testOptions, async () => {
    const sites = [
      ['https://test/1/1'],
      ['https://test/2/1', 'https://test/2/2'],
      ['https://test/3/1', 'https://test/3/2', 'https://test/3/3'],
      ['https://test/4/1', 'https://test/4/2', 'https://test/4/3', 'https://test/4/4'],
      [
        'https://test/5/1',
        'https://test/5/2',
        'https://test/5/3',
        'https://test/5/4',
        'https://test/5/5'
      ]
    ]

    checkLog('[start]')

    const result = await pMap(sites, mapper2_max)

    console.log(result)
  })
})
```

実行結果
```ts
time : 2025-01-18T04:37:49.044Z - text: [start]
time : 2025-01-18T04:37:50.049Z - text: mapper2-index = 1
time : 2025-01-18T04:37:51.063Z - text: mapper2-index = 2
time : 2025-01-18T04:37:51.063Z - text: https://test/1/1
time : 2025-01-18T04:37:52.048Z - text: mapper2-index = 3
time : 2025-01-18T04:37:52.065Z - text: https://test/2/1
time : 2025-01-18T04:37:53.046Z - text: mapper2-index = 4
time : 2025-01-18T04:37:53.062Z - text: https://test/3/1
time : 2025-01-18T04:37:53.078Z - text: https://test/2/2
time : 2025-01-18T04:37:54.047Z - text: mapper2-index = 5
time : 2025-01-18T04:37:54.048Z - text: https://test/4/1
time : 2025-01-18T04:37:54.062Z - text: https://test/3/2
time : 2025-01-18T04:37:55.050Z - text: https://test/4/2
time : 2025-01-18T04:37:55.050Z - text: https://test/5/1
time : 2025-01-18T04:37:55.052Z - text: https://test/3/3
time : 2025-01-18T04:37:56.050Z - text: https://test/4/3
time : 2025-01-18T04:37:56.051Z - text: https://test/5/2
time : 2025-01-18T04:37:57.054Z - text: https://test/4/4
time : 2025-01-18T04:37:57.055Z - text: https://test/5/3
time : 2025-01-18T04:37:58.050Z - text: https://test/5/4
time : 2025-01-18T04:37:59.052Z - text: https://test/5/5
[
  'https://test/1 - 2000',
  'https://test/2 - 4000',
  'https://test/3 - 6000',
  'https://test/4 - 8000',
  'https://test/5 - 10000'
]
```


### 全部同時実行からの直列実行

```plantuml
@startuml
robust "全体" as all

concise "https://test/1" as test1
concise "https://test/1/1" as test1_1

concise "https://test/2" as test2
concise "https://test/2/1" as test2_1
concise "https://test/2/2" as test2_2

concise "https://test/3" as test3
concise "https://test/3/1" as test3_1
concise "https://test/3/2" as test3_2
concise "https://test/3/3" as test3_3

concise "https://test/4" as test4
concise "https://test/4/1" as test4_1
concise "https://test/4/2" as test4_2
concise "https://test/4/3" as test4_3
concise "https://test/4/4" as test4_4

concise "https://test/5" as test5
concise "https://test/5/1" as test5_1
concise "https://test/5/2" as test5_2
concise "https://test/5/3" as test5_3
concise "https://test/5/4" as test5_4
concise "https://test/5/5" as test5_5

@all
0 is 待機中
+1 is 処理中
+20 is 待機中

@test1
1 is 処理中
+1 is {hidden}
@test1_1
2 is 処理中
+1 is {hidden}

@test2
1 is 処理中
+2 is {hidden}
@test2_1
3 is 処理中
+1 is {hidden}
@test2_2
4 is 処理中
+2 is {hidden}

@test3
1 is 処理中
+3 is {hidden}
@test3_1
4 is 処理中
+1 is {hidden}
@test3_2
5 is 処理中
+2 is {hidden}
@test3_3
7 is 処理中
+3 is {hidden}

@test4
1 is 処理中
+4 is {hidden}
@test4_1
5 is 処理中
+1 is {hidden}
@test4_2
6 is 処理中
+2 is {hidden}
@test4_3
8 is 処理中
+3 is {hidden}
@test4_4
11 is 処理中
+4 is {hidden}

@test5
1 is 処理中
+5 is {hidden}
@test5_1
6 is 処理中
+1 is {hidden}
@test5_2
7 is 処理中
+2 is {hidden}
@test5_3
9 is 処理中
+3 is {hidden}
@test5_4
12 is 処理中
+4 is {hidden}
@test5_5
16 is 処理中
+5 is {hidden}

@enduml
```

```ts
import { describe, test } from 'vitest'
import pMap from 'p-map'

const sleep = (wait: number) =>
  new Promise((resolve) => {
    setTimeout(() => resolve(wait), wait)
  })

function checkLog(text: string) {
  console.log(`time : ${new Date().toISOString()} - text: ${text}`)
}

const testOptions = {
  timeout: 1000 * 100
}

function sum(a: number, b: number) {
  return a + b
}

const mapper1 = async (site: string) => {
  const index = site.slice(-1)
  const wait = Number(index) * 1000
  const _wait = await sleep(wait)
  checkLog(site)
  return `${site} - ${_wait}`
}
function getWaitFromMapper1Message(mapper1Message: string) {
  const mapper1WaitString = mapper1Message.substring(mapper1Message.indexOf('-') + 1)
  const mapper1Wait = Number(mapper1WaitString)
  return mapper1Wait
}

const mapper2_sum = async (sites: string[]) => {
  const site = sites[0]
  const index = site.substring(site.length - 3, site.length - 2)
  const wait = Number(index) * 1000
  const _wait = (await sleep(wait)) as number
  checkLog(`mapper2-index = ${index}`)

  const concurrency = 1
  const result = await pMap(sites, mapper1, { concurrency })
  const waitResults = result.map(getWaitFromMapper1Message)
  const sumWait = waitResults.reduce(sum, 0)
  return `${site.substring(0, site.length - 2)} - ${_wait + sumWait}`
}

describe('p-map 非同期処理２つの配列', () => {
  test('使い方４ー全部同時実行からの直列実行', testOptions, async () => {
    const sites = [
      ['https://test/1/1'],
      ['https://test/2/1', 'https://test/2/2'],
      ['https://test/3/1', 'https://test/3/2', 'https://test/3/3'],
      ['https://test/4/1', 'https://test/4/2', 'https://test/4/3', 'https://test/4/4'],
      [
        'https://test/5/1',
        'https://test/5/2',
        'https://test/5/3',
        'https://test/5/4',
        'https://test/5/5'
      ]
    ]

    checkLog('[start]')

    const result = await pMap(sites, mapper2_sum)

    console.log(result)
  })
})
```

実行結果
```ts
time : 2025-01-18T04:46:08.872Z - text: [start]
time : 2025-01-18T04:46:09.888Z - text: mapper2-index = 1
time : 2025-01-18T04:46:10.875Z - text: mapper2-index = 2
time : 2025-01-18T04:46:10.894Z - text: https://test/1/1
time : 2025-01-18T04:46:11.876Z - text: mapper2-index = 3
time : 2025-01-18T04:46:11.877Z - text: https://test/2/1
time : 2025-01-18T04:46:12.888Z - text: mapper2-index = 4
time : 2025-01-18T04:46:12.888Z - text: https://test/3/1
time : 2025-01-18T04:46:13.889Z - text: mapper2-index = 5
time : 2025-01-18T04:46:13.890Z - text: https://test/2/2
time : 2025-01-18T04:46:13.890Z - text: https://test/4/1
time : 2025-01-18T04:46:14.906Z - text: https://test/3/2
time : 2025-01-18T04:46:14.907Z - text: https://test/5/1
time : 2025-01-18T04:46:15.906Z - text: https://test/4/2
time : 2025-01-18T04:46:16.922Z - text: https://test/5/2
time : 2025-01-18T04:46:17.906Z - text: https://test/3/3
time : 2025-01-18T04:46:18.906Z - text: https://test/4/3
time : 2025-01-18T04:46:19.924Z - text: https://test/5/3
time : 2025-01-18T04:46:22.908Z - text: https://test/4/4
time : 2025-01-18T04:46:23.926Z - text: https://test/5/4
time : 2025-01-18T04:46:28.927Z - text: https://test/5/5
[
  'https://test/1 - 2000',
  'https://test/2 - 5000',
  'https://test/3 - 9000',
  'https://test/4 - 14000',
  'https://test/5 - 20000'
]
```



### 全部同時実行からの最大２個まで同時実行

```plantuml
@startuml
robust "全体" as all

concise "https://test/1" as test1
concise "https://test/1/1" as test1_1

concise "https://test/2" as test2
concise "https://test/2/1" as test2_1
concise "https://test/2/2" as test2_2

concise "https://test/3" as test3
concise "https://test/3/1" as test3_1
concise "https://test/3/2" as test3_2
concise "https://test/3/3" as test3_3

concise "https://test/4" as test4
concise "https://test/4/1" as test4_1
concise "https://test/4/2" as test4_2
concise "https://test/4/3" as test4_3
concise "https://test/4/4" as test4_4

concise "https://test/5" as test5
concise "https://test/5/1" as test5_1
concise "https://test/5/2" as test5_2
concise "https://test/5/3" as test5_3
concise "https://test/5/4" as test5_4
concise "https://test/5/5" as test5_5

@all
0 is 待機中
+1 is 処理中
+14 is 待機中

@test1
1 is 処理中
+1 is {hidden}
@test1_1
2 is 処理中
+1 is {hidden}

@test2
1 is 処理中
+2 is {hidden}
@test2_1
3 is 処理中
+1 is {hidden}
@test2_2
3 is 処理中
+2 is {hidden}

@test3
1 is 処理中
+3 is {hidden}
@test3_1
4 is 処理中
+1 is {hidden}
@test3_2
4 is 処理中
+2 is {hidden}
@test3_3
5 is 処理中
+3 is {hidden}

@test4
1 is 処理中
+4 is {hidden}
@test4_1
5 is 処理中
+1 is {hidden}
@test4_2
5 is 処理中
+2 is {hidden}
@test4_3
6 is 処理中
+3 is {hidden}
@test4_4
7 is 処理中
+4 is {hidden}

@test5
1 is 処理中
+5 is {hidden}
@test5_1
6 is 処理中
+1 is {hidden}
@test5_2
6 is 処理中
+2 is {hidden}
@test5_3
7 is 処理中
+3 is {hidden}
@test5_4
8 is 処理中
+4 is {hidden}
@test5_5
10 is 処理中
+5 is {hidden}

@enduml
```

```ts
import { describe, test } from 'vitest'
import pMap from 'p-map'

const sleep = (wait: number) =>
  new Promise((resolve) => {
    setTimeout(() => resolve(wait), wait)
  })

function checkLog(text: string) {
  console.log(`time : ${new Date().toISOString()} - text: ${text}`)
}

const testOptions = {
  timeout: 1000 * 100
}

function array_slice_2(acc: number[][], cur: number) {
  const topLengt = acc.length
  if (topLengt == 0) {
    acc.push([cur])
  } else if (acc[topLengt - 1].length == 2) {
    acc.push([cur])
  } else {
    acc[topLengt - 1].push(cur)
  }

  return acc
}

function array_sum_slice_2(acc: number[], cur: number[]) {
  const accLengt = acc.length
  if (accLengt == 0) {
    acc.push(...cur)
  } else {
    const curLength = cur.length
    const min = Math.min(acc[0], acc[1])
    const minIndex = acc[0] == min ? 0 : 1
    acc[minIndex] += cur[0]

    if (curLength == 2) {
      const min2 = Math.min(acc[0], acc[1])
      const min2Index = acc[0] == min2 ? 0 : 1
      acc[min2Index] += cur[1]
    }
  }

  return acc
}

const mapper1 = async (site: string) => {
  const index = site.slice(-1)
  const wait = Number(index) * 1000
  const _wait = await sleep(wait)
  checkLog(site)
  return `${site} - ${_wait}`
}
function getWaitFromMapper1Message(mapper1Message: string) {
  const mapper1WaitString = mapper1Message.substring(mapper1Message.indexOf('-') + 1)
  const mapper1Wait = Number(mapper1WaitString)
  return mapper1Wait
}

const mapper2_limit2 = async (sites: string[]) => {
  const site = sites[0]
  const index = site.substring(site.length - 3, site.length - 2)
  const wait = Number(index) * 1000
  const _wait = (await sleep(wait)) as number
  checkLog(`mapper2-index = ${index}`)

  const concurrency = 2
  const result = await pMap(sites, mapper1, { concurrency })
  const waitResults = result.map(getWaitFromMapper1Message)
  const waitResultsArray = waitResults.reduce(array_slice_2, [])
  const waitResultsArraySum = waitResultsArray.reduce(array_sum_slice_2, [])
  const sumWait = Math.max(...waitResultsArraySum)
  return `${site.substring(0, site.length - 2)} - ${_wait + sumWait}`
}

describe('p-map 非同期処理２つの配列', () => {
  test('使い方６ー全部同時実行からの最大２個まで同時実行', testOptions, async () => {
    const sites = [
      ['https://test/1/1'],
      ['https://test/2/1', 'https://test/2/2'],
      ['https://test/3/1', 'https://test/3/2', 'https://test/3/3'],
      ['https://test/4/1', 'https://test/4/2', 'https://test/4/3', 'https://test/4/4'],
      [
        'https://test/5/1',
        'https://test/5/2',
        'https://test/5/3',
        'https://test/5/4',
        'https://test/5/5'
      ]
    ]

    checkLog('[start]')

    const result = await pMap(sites, mapper2_limit2)

    console.log(result)
  })
})
```

実行結果
```ts
time : 2025-01-18T04:51:38.465Z - text: [start]
time : 2025-01-18T04:51:39.473Z - text: mapper2-index = 1
time : 2025-01-18T04:51:40.482Z - text: mapper2-index = 2
time : 2025-01-18T04:51:40.482Z - text: https://test/1/1
time : 2025-01-18T04:51:41.473Z - text: mapper2-index = 3
time : 2025-01-18T04:51:41.489Z - text: https://test/2/1
time : 2025-01-18T04:51:42.470Z - text: mapper2-index = 4
time : 2025-01-18T04:51:42.487Z - text: https://test/3/1
time : 2025-01-18T04:51:42.488Z - text: https://test/2/2
time : 2025-01-18T04:51:43.469Z - text: mapper2-index = 5
time : 2025-01-18T04:51:43.470Z - text: https://test/4/1
time : 2025-01-18T04:51:43.486Z - text: https://test/3/2
time : 2025-01-18T04:51:44.470Z - text: https://test/5/1
time : 2025-01-18T04:51:44.471Z - text: https://test/4/2
time : 2025-01-18T04:51:45.470Z - text: https://test/5/2
time : 2025-01-18T04:51:45.487Z - text: https://test/3/3
time : 2025-01-18T04:51:46.470Z - text: https://test/4/3
time : 2025-01-18T04:51:47.484Z - text: https://test/5/3
time : 2025-01-18T04:51:48.472Z - text: https://test/4/4
time : 2025-01-18T04:51:49.472Z - text: https://test/5/4
time : 2025-01-18T04:51:52.487Z - text: https://test/5/5
[
  'https://test/1 - 2000',
  'https://test/2 - 4000',
  'https://test/3 - 7000',
  'https://test/4 - 10000',
  'https://test/5 - 14000'
]
```