1

I need to make API inside the map function. code is not waiting to complete the map function loop when i use the setTimeout function. In this below code "All api action completed" log should show after completed the API call with setTimeout. kindly suggest the solution.

    async function FieldMapping() {
        let data = [
            {
                "contractID": "D3047-IND-001",
                "fieldValues": {
                    "custrecord_vgicp_add_insurance_expense": "3000",
                    "custrecord_vgicp_advancespaid": "2000",
                    "custrecord_vgicp_allow_food_other": "3000"
                }
            },
            {
                "contractID": "D3048-IND-003",
                "fieldValues": {
                    "custrecord_vgicp_add_insurance_expense": "3700",
                    "custrecord_vgicp_advancespaid": "3700",
                    "custrecord_vgicp_allow_food_other": "3700"
                }
            },
            {
                "contractID": "D3049-IND-001",
                "fieldValues": {
                    "custrecord_vgicp_add_insurance_expense": "3700",
                    "custrecord_vgicp_advancespaid": "3700",
                    "custrecord_vgicp_allow_food_other": "3700"
                }
            },
            {
                "contractID": "D3081-FRA-002",
                "fieldValues": {
                    "custrecord_vgicp_add_insurance_expense": "3700",
                    "custrecord_vgicp_advancespaid": "3700",
                    "custrecord_vgicp_allow_food_other": "3700"
                }
            },
            {
                "contractID": "D3106-IND-002",
                "fieldValues": {
                    "custrecord_vgicp_add_insurance_expense": "2000",
                    "custrecord_vgicp_advancespaid": "2000",
                    "custrecord_vgicp_allow_food_other": "2000"
                }
            }
        ]
    
        await Promise.all(data.map(async(payroll, index)=> {
            setTimeout(async () => {
                let result = await apiCall(payroll)
                console.log("result:::", result)
            }, 1000*index+1 )
 
        }))
console.log("All API Action completed...")
    }
    
    async function apiCall() {
        //api call here
    }
  • 2
    Why not just `await Promise.all(data.map(payroll => apiCall(payroll)))` ? – Andreas Oct 19 '22 at 11:58
  • need to provide some time delay for API call otherwise it will throw error – mani kandan Oct 19 '22 at 12:01
  • What is the reason why you want to use `setTimeout`? You don't want the requests to be made immediately? You want a request to finish first before a next one is made? – trincot Oct 19 '22 at 12:02

3 Answers3

0

You need to return a promise from the map callback

    await Promise.all(data.map(async(payroll, index) => {
        return new Promise((resolve, reject) => setTimeout(async() => {
            try {
              let result = await apiCall(payroll)
              resolve(result)
            } catch (e) {
              reject()
            }
        }, 1000 * index + 1)

     }))

Mina
  • 14,386
  • 3
  • 13
  • 26
  • 1
    its working as per expected... thanks a lot – mani kandan Oct 19 '22 at 12:13
  • 1
    You are using the [promise constructor antipattern](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it) – trincot Oct 19 '22 at 12:26
  • An async function returns a promise. Consider removing that keyword? – evolutionxbox Oct 19 '22 at 12:34
  • @evolutionxbox, sorry, maybe there is a misunderstanding, I meant by `promise` is `promise constructor` he needs to return it so he can resolve after waiting for the `setTimeout` callback execution and `apiCall` async method because with the OP question each callback will not `await` them and all promises will be resolved with `undefined`. – Mina Oct 19 '22 at 14:38
0

I'm not entirely sure what you want to achieve with the the setTimeout. Feels to me like it's a bad idea. Try to get all your data first THEN do whatever you need to do with it.

const promises = data.map((payroll) => apiCall(payroll));

Promise.all(promises).then((result) => {
  console.log("All API Action completed...", result);
});
0

The callback passed to data.map will always return a promise that immediately resolves to undefined.

It seems you don't actually want to initiate all requests immediately. In that case, why not wait for the previous request to finish first before making the next? Also, when working with promises, it is more elegant to also promisify setTimeout.

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

async function FieldMapping() {
    // ...

    let duration = 0;
    for (const payroll of data) {
        await delay(duration);
        const result = await apiCall(payroll);
        console.log("result:::", result);
        duration = 1000;
    }
}
trincot
  • 317,000
  • 35
  • 244
  • 286