Executing a function without a callback within an Async library

I am facing an issue with this particular example mentioned in the Async documentation:

async.map(['file1','file2','file3'], fs.stat, function(err, results) {
   // results is now an array of stats for each file
});

In this example, the fs.stat function is called for each element in the array using (item,callback), but I am confused about which callback function to use and where it is defined.

Answer №1

To streamline your code, consider utilizing node's built-in util.promisify instead of relying on async.map and async.js:

const { promisify } = require('util')

const fs = require('fs')

const files = ['file1', 'file2', 'file3']

Promise.all(files.map(promisify(fs.stat)))
  .then(results => /* results is now an array of stats for each file */)
  .catch(err => /* err is the first error to occur */)

Promises have become the go-to method for handling concurrency in modern JavaScript environments. They can seamlessly replace node-style error-first callbacks, following the format of (err, res) => { ... }, which is commonly seen with async.map.

Promises offer a solution to the issues associated with "callback hell" and provide a cleaner approach to asynchronous programming. If you still prefer using node-style callbacks, the below example showcasing asyncMap and an async function demonstrates the orchestration of callbacks:

// Code example demonstrating asyncMap functionality

// Define a function that doubles a number after a delay
const delayedDouble = (x, callback) =>
  setTimeout
    ( () =>
        callback
          ( null
          , x * 2
          )
    , 1000
    )

// Implement asyncMap to handle async operations and callbacks
const asyncMap = (arr, func, cb) =>
{ const loop = (res, i) =>
    i >= arr.length
      ? cb(null, res)
      : func
          ( arr[i]
          , (err, x) =>
              err
                ? cb(err, null)
                : loop
                    ( [ ...res, x ]
                    , i + 1
                    )
          )
  return loop
     ( []
     , 0
     ) 
}
  
// Demonstrate the usage of asyncMap with a delayedDouble function
asyncMap
  ( [ 1, 2, 3 ]
  , delayedDouble
  , (err, res) =>
      err
        ? console.error('error', err)
        : console.log('result', res)
  )
  
console.log('please wait 3 seconds...')
// please wait 3 seconds...
// <3 seconds later>
// result [ 2, 4, 6 ]

In the event of a potential error, asyncMap handles error propagation effectively:

// Example showcasing error handling in asyncMap

const tenDividedBy = (x, callback) =>
  setTimeout
    ( () =>
        x === 0
          ? callback(Error('cannot divide 10 by zero'), null)
          : callback(null, 10 / x)
    , 1000
    )

asyncMap
  ( [ 1, 0, 6 ]
  , tenDividedBy
  , (err, res) =>
      err
        ? console.error('error', err)
        : console.log('result', res)
  )
  // error Error: cannot divide 10 by zero

When executed without errors, asyncMap returns the results as expected:

asyncMap
  ( [ 1, 2, 3, ]
  , tenDividedBy
  , (err, res) =>
      err
        ? console.error('error', err)
        : console.log('result', res)
  )
  // result [ 10, 5, 3.3333333333333335 ]

Transitioning to Promises offers a more streamlined approach, reducing callback nesting and providing automatic error handling:

// Refactored example using Promises for smoother asynchronous operations

// Implement asyncMap using Promises
const asyncMap = (arr, func) =>
{ const loop = (res, i) =>
    i >= arr.length
      ? Promise.resolve(res)
      : func(arr[i]).then(x => loop([...res, x], i + 1))
  return loop ([], 0)
}

// Function using Promises to handle division
const tenDividedBy = x =>
  x === 0
    ? Promise.reject(Error('cannot divide 10 by zero'))
    : Promise.resolve(10 / x)

// Demonstrate the usage of asyncMap with Promises
asyncMap([1, 2, 0], tenDividedBy)
  .then(res => console.log('result', res))
  .catch(err => console.error('error', err))
// Error: cannot divide 10 by zero

asyncMap([1, 2, 3], tenDividedBy)
  .then(res => console.log('result', res))
  .catch(err => console.error('error', err))
// result [ 10, 5, 3.3333 ]

While manual implementation is great for learning purposes, leveraging Promise.all eliminates the need for custom solutions like asyncMap and offers parallel processing for enhanced efficiency.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Retrieving Progress Updates from a PHP Script Using XMLHttpRequest

I am currently using JavaScript to execute an XMLHttpRequest to a PHP script that returns data. My goal is to display a progress bar for the user instead of a spinning circle, indicating the progress of fetching and receiving the data. While I understand t ...

Verifying the username's availability through AJAX requests

My registration form utilizing AJAX isn't connecting to the database. It seems like I'm missing something important. Let's focus on validating this particular field: Username:<input type="text" name="user" id="user" maxlength="30"> & ...

When you hover over HTML tables, they dynamically rearrange or shift positions

Issue: I am encountering a problem with multiple tables where, upon hovering over a row, the tables are floating rather than remaining fixed in place. Additionally, when hovering over rows in the first or second table, the other tables start rendering unex ...

Stop the upload progress in Angular 6 by unsubscribing from the upload observable, without halting the actual

When attempting to cancel an upload by unsubscribing, the unsubscribe action only stops the progress of the upload from being displayed, but the actual upload process continues and files are still uploaded to the server. This issue is present in the upload ...

What is the best way to retrieve a state variable within the getServerSideProps() function in NextJS?

Introduction Greetings everyone, I am a newcomer to NextJS. Currently, I am in the process of developing a weather application that utilizes external APIs. My main task involves fetching data from an API and displaying it on the frontend. Desired Function ...

Create the key's value in a dynamic manner within localforage

When utilizing localForage to store data offline, I encountered an issue with generating unique key values for each form submission. My goal is to have the key value generated dynamically as 'activity_1', 'activity_2', 'activity_3& ...

Sending Data via Ajax

I am currently working on implementing an ajax invitation script that allows users to invite their friends to an event. The javascript code I have used in other parts of the website works perfectly, but for some reason, it is not functioning correctly in t ...

The sendFile function fails to transmit any data

Currently working on integrating the mailChimp API into my project, but facing an issue with the resFile code that handles sending the success response. The current code snippet: async function run(){ try { const res = await mailch ...

In order to display the particle-slider logo effect, the JavaScript on the page needs to be refreshed

I have a website frontend integrated from WordPress using an HTML 5 Blank Child Theme. The site features a logo effect utilizing particle slider for screen sizes greater than 960px, and a flat logo image for screen sizes less than 960px. Everything works p ...

Is there a way to attach an event for multiple arithmetic operations to a checkbox?

My form includes 4 checkboxes for different mathematical operations. <form action="" method="POST"> Select number of questions: <input type="number" name="que" value="que"> <br> <br> Select number of series: <select name="sel ...

Using jQuery to include a sub-object in the "data" object for each AJAX request made on the webpage

Is there a way to enhance the functionality of jQuery.ajax by including a static sub-data object in every ajax request automatically? For instance, for an ajax request like this: jQuery.ajax({ url: 'request_file.php', data: { da ...

Submit form using jQuery after making an AJAX request with jQuery's $

I'm working on the following code: $.get(link, function(data, status) { document.getElementById("test").value = data; }); $('#formtest').submit(); Everything works fine in Firefox, but in Google Chrome the submit is done before t ...

Merge rxjs streams, identify modifications, and yield a single result

In the context of using Angular with .net Core WebApi, let's consider the development of a time management application designed to monitor task durations. The user initiates a task on the front end which triggers a timer displaying elapsed time. The ...

Tips for utilizing the onload function in jquery

Having an issue where I have a button that I want to set time, and in order for the function to run correctly, it needs to be defined on the body element. This works fine with plain JavaScript, but I am encountering an error when trying to use jQuery. < ...

Utilize React JS to parse and display a sophisticated JSON structure in a dropdown menu

Looking at the backend data structure provided, we have information on various courses in different departments. { "courseDetails" : [{"departmentId" : 105654, "courses" : [{"stream" : "science","courseIds" : ["104","105 ...

Tips for maintaining authentication in a Next.js application with Firebase even when tokens expire or the page is refreshed

Struggling with firebase authentication flows while building an app using firebase and next.js. Everything was going smoothly until I encountered a bug or error. When my computer remains logged in to the app for some time and I refresh the page, it redirec ...

Discover an Easy Way to Scroll to the Bottom of Modal Content with Bootstrap 5 on Your Razor Page

Currently, I am developing a web application that utilizes Razor Pages and Bootstrap 5 modals to showcase dynamic content. The challenge I am facing is ensuring that the content inside the modal automatically scrolls to the bottom when the modal opens or w ...

I am interested in utilizing $axios in conjunction with Vuex constants for my project

My Dream Becoming Reality I frequently use this.$axios, so I attempted to store it in a constant, but unfortunately, it did not work as expected. Despite reading the official documentation, I couldn't grasp the reason behind this issue. Could it be d ...

Failed submission: XMLHttpRequest and FormData not processing data correctly

I'm attempting to use AJAX to submit a form using the post method along with a FormData object. Here's a simplified version of the JavaScript code: var form=…; // form element var url=…; // action form['update'].onclick=function ...

Issue with SVG on tainted canvas causes IE security error when using toDataURL

In my Angular JS directive, I have implemented a feature to export SVGs to PNG. While this functionality works seamlessly in most browsers, it encounters a security error in IE. Despite my numerous attempts to troubleshoot the issue, I have been unable to ...