# Async Operations!

**URL:** <https://community.postman.com/t/async-operations/24314>\
**Category:** Help Hub\
**Tags:** request, async\
**Created:** [May 31, 2021, 9:18pm UTC](https://community.postman.com/t/async-operations/24314 "2021-05-31T21:18:50Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![singhsivcan](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/singhsivcan/32/1595_2.png) [@singhsivcan](https://community.postman.com/u/singhsivcan)\
**Post date:** [May 31, 2021, 9:18pm UTC](https://community.postman.com/t/async-operations/24314/1 "2021-05-31T21:18:50Z")

</div>

I was working with a colleague and we were trying to achieve something by chaining multiple requests as a pre-step before the actual request happened.

**Use case:**  
We wanted to call 3-4 specific endpoints in a specific order and gather all the required data before the actual request was sent out.

One way was to do it by creating multiple requests and using the collection runner. But the other way was to make use of `pm.sendRequest`, however, there’s no guarantee in which order multiple of `pm.sendRequest` would execute during the execution phase of the script.

So, I ended up creating 2 operations of the famous async library (probably will work on adding more) in the most naive way as possible, but it works so… ¯\_(ツ)_/¯

This is just an example to showcase what’s do-able using scripts, and how a lot of things can be achieved with chaining everything in just one request.

**Reference:**  
See the pre-request scripts of each request in the following collection and [fork](https://learning.postman.com/docs/collaborating-in-postman/version-control-for-collections/#forking-a-collection) the collection if you want to try it out:

> **[Postman](https://www.postman.com/postman/workspace/postman-answers/collection/3407886-220af2f6-63f2-4d84-903d-99e6e296a8c8?ctx=documentation)**

**Example code snippet:**

```javascript
// Expected output in console: 3, 1, 2
asyncSeries([
    (cb) => pm.sendRequest('https://postman-echo.com/delay/3', (err, res) => {
        console.log(res.json().delay);
        cb(err, res);
    }),
    (cb) => pm.sendRequest('https://postman-echo.com/delay/1', (err, res) => {
        console.log(res.json().delay);
        cb(err, res);
    }),
    (cb) => pm.sendRequest('https://postman-echo.com/delay/2', (err, res) => {
        console.log(res.json().delay);
        cb(err, res);
    })
], (err, res) => {
    console.log('Series operations resolved', err, res);
});

```

**Screenshot:**

 ![image](https://us1.discourse-cdn.com/getpostman/original/3X/b/1/b1a701afb75dd6c2cc54eda56b9a5a641d018139.png)

---

<div class="post-metadata">

**Author:** ![sean.keegan](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/sean.keegan/32/6353_2.png) [@sean.keegan](https://community.postman.com/u/sean.keegan)\
**Post date:** [June 2, 2021, 7:22pm UTC](https://community.postman.com/t/async-operations/24314/2 "2021-06-02T19:22:43Z")

</div>

This is awesome @singhsivcan! Thanks for putting this in a collection that I can play around on my own.

And that documentation in the Pre-request tabs?! 😻 😻 😻

---

<div class="post-metadata">

**Author:** ![praveendvd](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/praveendvd/32/6796_2.png) [@praveendvd](https://community.postman.com/u/praveendvd)\
**Post date:** [June 2, 2021, 10:02pm UTC](https://community.postman.com/t/async-operations/24314/3 "2021-06-02T22:02:51Z")

</div>

@singhsivcan It looks great! just had a question is there any drawbacks for below approaches when compared to this

**Approach 1**

```auto
pm.sendRequest("https://postman-echo.com/delay/6", (error, res) => {

    console.log(res)

    pm.sendRequest("https://postman-echo.com/delay/1", (error, res) => {

        console.log(res)

        pm.sendRequest("https://postman-echo.com/delay/2", (error, res) => {

            console.log(res)

        })

    })

})

```

**Approach 2:**

```auto

pm.environment.set("final", [])

let promisify = function (req) {

    return new Promise((resolve, reject) => {

        pm.sendRequest(req, (error, res) => {

            setTimeout(resolve(res), 1);

        })

    });

};

async function test() {

    await promisify("https://postman-echo.com/delay/3")

    await promisify("https://postman-echo.com/delay/1")

    await promisify("https://postman-echo.com/delay/2")

}

test()

//set time out to the max response time of the 3 requests

// here 3000 or 3 sec is the highest so we are keeping 5000

setTimeout(()=>{},5000)

```

---

<div class="post-metadata">

**Author:** ![singhsivcan](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/singhsivcan/32/1595_2.png) [@singhsivcan](https://community.postman.com/u/singhsivcan)\
**Post date:** [June 2, 2021, 11:00pm UTC](https://community.postman.com/t/async-operations/24314/4 "2021-06-02T23:00:59Z")

</div>

@sean.keegan Thanks, I am glad it’s useful!

@praveendvd Thanks for sharing your thoughts. My thoughts over the approaches you shared:  
**Approach 1** : **Callback hell!** Yes, that’s what promises help you avoid, but currently the Postman script execution doesn’t support promises. So for lot of operations, this approach becomes a really big problem.

**Approach 2:** You’re kind of simulating a race situation here since again promises don’t work as you’d expect them to in the postman eco-system. I’ve personally found async library’s ways of working with callbacks pretty awesome and that’s why I prefer going with the approach that we used in the requests.  
Also, since you’ve tried to simulate a race condition here, I added it as a new request in the collection itself: [async.race](https://www.postman.com/postman/workspace/postman-answers/request/3407886-0b2819bc-b2e9-4de5-91da-694feaee8bfe) !

 ![image](https://us1.discourse-cdn.com/getpostman/original/3X/4/4/44f000a1a3f1f8469a3b86d97b404dace4676b18.png)

---

<div class="post-metadata">

**Author:** ![praveendvd](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/praveendvd/32/6796_2.png) [@praveendvd](https://community.postman.com/u/praveendvd)\
**Post date:** [June 3, 2021, 4:35pm UTC](https://community.postman.com/t/async-operations/24314/5 "2021-06-03T16:35:25Z")

</div>

@singhsivcan😍 😍 Thank you so much. That’s really cool , i simplified that code by calling the cdn equalent of the async library . Really thanks for this learned something new today

```auto

// calling async library cdn function

pm.sendRequest("https://cdnjs.cloudflare.com/ajax/libs/async/3.2.0/async.js", (error, res) => {

    //initializing async

    (new Function(res.text()))();

    //create a call back function that will act as the iteratee

    //we should call callback() for the async library to work

    let requestCallbackWrapper = function (req, callback) {

        pm.sendRequest(req, (error, res) => {

            console.log(res.json())

            callback()

        })

    };

    //pass the urls as array in order

    //each item and a callback will be passed to iteratee we created

    async.eachSeries(["https://postman-echo.com/delay/3", "https://postman-echo.com/delay/5", "https://postman-echo.com/delay/1"], requestCallbackWrapper, function (err) {

        console.log(err);

    });

});

```

---

<div class="post-metadata">

**Author:** ![praveendvd](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/praveendvd/32/6796_2.png) [@praveendvd](https://community.postman.com/u/praveendvd)\
**Post date:** [June 3, 2021, 8:22pm UTC](https://community.postman.com/t/async-operations/24314/6 "2021-06-03T20:22:24Z")

</div>

@singhsivcan The above code works but if i try to use the same code again it will throw error cannot call eachSerise of undefined. Could you help me out i am not understanding whats wrong .

**steps to reproduce:**

1. Add the above script to both pre-request and test script
2. Now send the request

![image](https://us1.discourse-cdn.com/getpostman/original/3X/e/4/e4634592f3072c6ab923e75f0ef03564d83eb3a2.png)

---

<div class="post-metadata">

**Author:** ![praveendvd](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/praveendvd/32/6796_2.png) [@praveendvd](https://community.postman.com/u/praveendvd)\
**Post date:** [June 3, 2021, 8:48pm UTC](https://community.postman.com/t/async-operations/24314/7 "2021-06-03T20:48:06Z")

</div>

> [@praveendvd](#):
>
> ```auto
> // calling async library cdn function
> 
> pm.sendRequest("https://cdnjs.cloudflare.com/ajax/libs/async/3.2.0/async.js", (error, res) => {
> 
> //initializing async
> 
> ```

using min build works:

```auto

pm.sendRequest("https://cdnjs.cloudflare.com/ajax/libs/async/3.2.0/async.min.js", (error, res) => {

    //initializing async

    eval(res.text());

    //create a call back function that will act as the iteratee

    //we should call callback() for the async library to work

    let requestCallbackWrapper = function (req, callback) {

        pm.sendRequest(req, (error, res) => {

            console.log(res.json())

            callback()

        })

    };

    //pass the urls as array in order

    //each item and a callback will be passed to iteratee we created

    this.async.eachSeries(["https://postman-echo.com/delay/3", "https://postman-echo.com/delay/5", "https://postman-echo.com/delay/1"], requestCallbackWrapper, function (err) {

        console.log(err);

    });

});

```

---

<div class="post-metadata">

**Author:** ![erhhung-intel](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/erhhung-intel/32/8853_2.png) [@erhhung-intel](https://community.postman.com/u/erhhung-intel)\
**Post date:** [June 9, 2021, 5:41am UTC](https://community.postman.com/t/async-operations/24314/8 "2021-06-09T05:41:53Z")

</div>

> but currently the Postman script execution doesn’t support promises

Really? I use it to promisify `pm.sendRequest()` and with `async`/`await`:

_ **Collection pre-request script:** _

```js
// export common utility functions
pm.globals.set('util', String(() => ({

    // use the open interval hack to wait until async
    // operations are done before sending the request
    // in a pre-request script
    waitUntilDone(promise) {
        const wait = setInterval(() => {}, 300000);
        promise.finally(() => clearInterval(wait));
    },

    // promisified pm.sendRequest()
    sendRequest(req) {
        return new Promise(
            (resolve, reject) => pm.sendRequest(req, (err, res) => {
                if (!err && res.code / 100 < 4) return resolve(res);
                let message = `Request "${req.url||req}" failed (${res.code})`;
                if (err?.message) message += `: ${err.message}`;
                reject({message});
            }));
    },

    // load external library modules in order,
    // then return this[thisProp] or just this
    async loadModules(urls, thisProp=undefined) {
        const thisKeys = Object.keys(this);
        (await Promise.all(urls.map(this.sendRequest)))
            .forEach(res => eval(res.text()));

        const thisObj = _.omit(this, thisKeys);
        //console.log('KEYS: this', Object.keys(thisObj));
        return !thisProp && thisObj || thisObj[thisProp];
    },
})));

```

_ **Main request pre-request script:** _

```js
// import common utility functions
const util = eval(pm.globals.get('util'))();

async function echoDelay(secs) {
    const url = `https://postman-echo.com/delay/${secs}`;
    return (await util.sendRequest(url)).json().delay;
}

async function asyncSteps() {
    console.log(await echoDelay(3));
    console.log(await echoDelay(1));
    console.log(await echoDelay(2));

    // perform some other async file loading
    const {moment} = await util.loadModules([
        'https://momentjs.com/downloads/moment.min.js',
        'https://momentjs.com/downloads/moment-timezone-with-data.min.js',
    ]);
    const tsToDate = ts => {
        const date = new Date(ts);
        let str = moment(date).format('L hh:mm:ss');
        const tz = moment.tz(date, moment.tz.guess());
        const dur = moment.duration(date - new Date());
        return `${str} ${tz.zoneAbbr()} (${dur.humanize(true)})`;
    };
    console.log(tsToDate(1615715966000));
}
util.waitUntilDone(asyncSteps().catch(console.error));

```

---

<div class="post-metadata">

**Author:** ![singhsivcan](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/singhsivcan/32/1595_2.png) [@singhsivcan](https://community.postman.com/u/singhsivcan)\
**Post date:** [June 9, 2021, 11:30am UTC](https://community.postman.com/t/async-operations/24314/9 "2021-06-09T11:30:51Z")

</div>

It doesn’t in contrast with the native behaviour of promises, you cannot halt script execution where the script will wait till all your promises resolve/reject, the script execution only halts for setTimeout/Interval(s) or `pm.sendRequest` function calls, and this also is one way to hack around that you shared:

> [@erhhung-intel](#):
>
> ```auto
> // use the open interval hack to wait until async
> // operations are done before sending the request
> // in a pre-request script
> waitUntilDone(promise) {
> const wait = setInterval(() => {}, 300000);
> promise.finally(() => clearInterval(wait));
> },
> 
> ```

---

<div class="post-metadata">

**Author:** ![jprealini](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/jprealini/32/9270_2.png) [@jprealini](https://community.postman.com/u/jprealini)\
**Post date:** [September 30, 2021, 9:28pm UTC](https://community.postman.com/t/async-operations/24314/10 "2021-09-30T21:28:07Z")

</div>

Thanks @singhsivcan ! This helped me solve a scenario I had with multiple calls… Now, I question I have is… I am trying to assert at least the status code for each of the calls (three in fact)… But when any of them fail, instead of showing a FAIL test in the Test Results, it shows the infamous “AssertionError” red sign… Is there a way to make that work correctly?

Also… let’s say in the last call of the async series I need to delete some data I created in the first call of the series… but if any of the intermediate calls’ assertions fails, the serie is not completed, thus the data never gets deleted… is there a way to force the subsequent calls to be made even if a prior one has a failing assertion?

Thanks!

---

<div class="post-metadata">

**Author:** ![twnk](https://avatars.discourse-cdn.com/v4/letter/t/b77776/32.png) [@twnk](https://community.postman.com/u/twnk)\
**Post date:** [September 13, 2022, 3:43pm UTC](https://community.postman.com/t/async-operations/24314/11 "2022-09-13T15:43:33Z")

</div>

Hey @singhsivcan! This is fantastic, thank you 🙂 Could you clarify, is there currently a licence for this code?

---

<div class="post-metadata">

**Author:** ![singhsivcan](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/singhsivcan/32/1595_2.png) [@singhsivcan](https://community.postman.com/u/singhsivcan)\
**Post date:** [September 13, 2022, 4:00pm UTC](https://community.postman.com/t/async-operations/24314/12 "2022-09-13T16:00:56Z")

</div>

There isn’t any. Feel free to use it, however.

---

<div class="post-metadata">

**Author:** ![pauledwardsleo](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/pauledwardsleo/32/25947_2.png) [@pauledwardsleo](https://community.postman.com/u/pauledwardsleo)\
**Post date:** [September 13, 2023, 1:29am UTC](https://community.postman.com/t/async-operations/24314/13 "2023-09-13T01:29:14Z")

</div>

@singhsivcan thank you for sharing your Async Operations solution Collection.

However, it appears the `async.series` entry in the Collection may have been inadvertently clobbered because its `Pre-request Script` tab currently contains only this 1 line of code:

`console.log(pm.request.auth)`

---

<div class="post-metadata">

**Author:** ![singhsivcan](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/singhsivcan/32/1595_2.png) [@singhsivcan](https://community.postman.com/u/singhsivcan)\
**Post date:** [September 13, 2023, 1:58am UTC](https://community.postman.com/t/async-operations/24314/14 "2023-09-13T01:58:22Z")

</div>

Thank you for notifying me. Looks like it had been updated recently by someone. I’ve reverted it back. 😄

---

<div class="post-metadata">

**Author:** ![pauledwardsleo](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/pauledwardsleo/32/25947_2.png) [@pauledwardsleo](https://community.postman.com/u/pauledwardsleo)\
**Post date:** [September 27, 2023, 8:00pm UTC](https://community.postman.com/t/async-operations/24314/15 "2023-09-27T20:00:21Z")

</div>

@singhsivcan It appears that `lodash` is referenced in the `async.waterfall` example, but is not used.

Furthermore, it seems `lodash` is not actually required in any of these examples and could be refactored to use array `.length` instead. According to [benchmark evidence](https://measurethat.net/Benchmarks/Show/7158/0/length-vs-lodash-size) `.length` is about 4.3x faster than `lodash` `.size` and would require less memory overhead by not loading `lodash` at all.

---

<div class="post-metadata">

**Author:** ![yosrixp](https://avatars.discourse-cdn.com/v4/letter/y/ac91a4/32.png) [@yosrixp](https://community.postman.com/u/yosrixp)\
**Post date:** [December 28, 2023, 5:47am UTC](https://community.postman.com/t/async-operations/24314/16 "2023-12-28T05:47:31Z")

</div>

You can achieve multiple requests by using Promise.all i.e

```auto
const fetch = (req) => {
    return new Promise((resolve, reject) => {
        pm.sendRequest(req, (err, res) => {
            const resp = {};
            if (err) {
                reject({ reqId: err });
                return;
            }
            resp[req.reqId] = res.json()
            resolve(resp);
        });
    })
}

const promisify = async (requests) => {
    try {
        return await Promise.all(
            requests.map(req => fetch(req).then(res => res))
        )
    } catch (error) {
        console.log("Error", error)
    }
}

promisify([{
    reqId: 'delay3', url: 'https://127.0.0.1:4443/delay3'
},
{
    reqId: 'delay2', url: 'https://127.0.0.1:4443/delay2', method: 'POST',
    header: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    },
    body: JSON_REQUEST
},{
    reqId: 'delay1', url: 'https://127.0.0.1:4443/delay1'
}])
    .then(res => {
      // massage response or other data processing
}).then(res => {
// fire other calls or extra processing.
}).catch((error) => {
 // handle errors.
});

```

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/getpostman/user_avatar/community.postman.com/system/32/29796_2.png) [@system](https://community.postman.com/u/system)\
**Post date:** [December 12, 2024, 2:46pm UTC](https://community.postman.com/t/async-operations/24314/17 "2024-12-12T14:46:55Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
