npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

async-parallel-foreach

v1.0.1

Published

[![npm](https://img.shields.io/npm/v/async-parallel-foreach.svg)](https://www.npmjs.com/package/async-parallel-foreach) [![npm](./coverage/badge.svg)](https://github.com/Donaldcwl/async-parallel-foreach) [![npm](https://img.shields.io/npm/l/async-parallel

Downloads

1,347

Readme

Async parallel forEach

npm npm npm

Javascript module to perform async flow control on collection/iterable/dictionary in controlled parallel and make retry easily when error occurred

Features

  • iterate collection (array/object/iterator) and run async function on each item in a collection
  • control the concurrency of running async function on the items
  • auto retry when error occurred
  • delayed retry

Install

npm install async-parallel-foreach async --save
or
yarn add async-parallel-foreach async

How to use this module in your project?

Frontend: used in framework like React, Angular, Vue etc (work with bundler like webpack and rollup)

import { asyncParallelForEach, BACK_OFF_RETRY } from 'async-parallel-foreach'

Backend: node.js

const { asyncParallelForEach, BACK_OFF_RETRY } = require('async-parallel-foreach')

API

Main function

asyncParallelForEach(coll: Collection, parallelLimit: number, iteratee: Function, eachMaxTry): Promise<Array<{ value: any, error: Error }>>

  • coll - can be Array, Object (dictionary), Iterable
  • parallelLimit - number of iteratee functions to be executed in parallel at any time, set parallelLimit = -1 for unlimited parallelization (all items will start process at once)
  • iteratee - the function that you define to process each item in "coll"
    • if "coll" is array, it will call with (value, index)
    • if "coll" is object, it will call with (value, key)
  • eachMaxTry - maximum number of times each item will be processed by "iteratee".
    • if eachMaxTry = 2, then the item will be retried 1 time when there is error throwed in the iteratee function
    • add delay before retry
      • set eachMaxTry = { times: 2, interval: 1000 } // wait for 1000 ms before retry
      • interval can also accept function returning the interval in ms
        • e.g. eachMaxTry = { times: 2, interval: (retryCount) => retryCount * 1000 } // retryCount start from 2 which means it is the 2nd trial

BACK_OFF_RETRY strategies

  • predefined interval function you may use

BACK_OFF_RETRY.randomBetween(minMs: number, maxMs: number)

  • e.g. eachMaxTry = { times: 5, interval: BACK_OFF_RETRY.randomBetween(100, 3000) } // random delay between 100ms and 3000ms

BACK_OFF_RETRY.exponential()

  • start from 100ms, then 200ms, 400ms, 800ms, 1600ms, ...

(details api document in here)

Usage

  • Example 1
const imageUrls = ['https://this-image-is-fine.jpg', 'https://this-image-does-exist-404.jpg', 'https://another-fine-image.jpg', /*......*/]

processImages(imageUrls).then(successFn).catch(errorCallback)

async function processImages(imageUrls) {

  const parallelLimit = 5 // process at most 5 images simultaneously
  
  const results = await asyncParallelForEach(imageUrls, parallelLimit, async (imageUrl, index) => {
    
    const filePath = await downloadImage(imageUrl)
    
    const convertedFilePath = await covertImageFormat(filePath)
    
    const compressFilePath = await compressImage(convertedFilePath)
    
    const s3ImageUrl = await uploadToS3(compressFilePath)
    
    // above operations may fails (throw Error) for any reason e.g. Network connection problem, image corruption, etc
    
    return s3ImageUrl
    
  }, { 
    times: 10,  // try at most 10 times
    interval: BACK_OFF_RETRY.exponential()
  })
  
  // results is in format [
  //   {value: '<the s3ImageUrl returned in the iteratee function corresponding to this-image-is-fine.jpg>' },
  //   {error: new Error('404 - Image not found')},
  //   {value: '<the s3ImageUrl returned in the iteratee function corresponding to another-fine-image.jpg>' },
  //   ......
  // ]
  
  return results
}
  • Example 2
const foods = {
  orange: ['anything1'],
  apple: 'anything2',
  banana: 100
}

processFoods(foods).then(successFn).catch(errorCallback)

async function processFoods(foods) {

  const parallelLimit = 2 // process at most 2 food simultaneously
  
  const results = await asyncParallelForEach(foods, parallelLimit, async (value, foodName) => {
    
    // if foodName === 'orange', then value will be ['anything1']
    // if foodName === 'apple', then value will be 'anything2'
    // if foodName === 'banana', then value will be 100
    
    const someResult = await someAsyncOperation(value)
    
    return someResult
    
  }, { 
    times: 3,  // try at most 3 times
    interval: BACK_OFF_RETRY.randomBetween(100, 3000)
  })
  
  // results is in format {
  //   orange: {value: '<someResult>' },
  //   apple: {value: '<someResult>' },
  //   banana: {error: new Error('some error if any')}
  // }
  
  return results
}

Example

Please check the "example" folder in this repo

  • How to run the example:
git clone https://github.com/Donaldcwl/async-parallel-foreach.git
cd async-parallel-foreach/example
yarn install # or npm install
node example.js

TODO FEATURES

  • get current status in the iteratee function e.g. currentTrial, isFirstTrial, isLastTrial, timeElapsed, failedReasons, incrementMaxTry
  • eachTrialTimeout, eachItemTimeout
  • run iteratee function in web worker for CPU intensive tasks (use tiny-worker for node.js)