0

I am trying to reduce an array of both asynchronous and synchronous methods. I have two synchronous methods and one asynchronous methods that does some basic formatting an object. Since I have a mix of asynchronous and synchronous methods, I am using async/await with my reduce. The problem is my formatName method returns the error Cannot read property 'toUpperCase' of undefined because the person parameter passed in is a promise. I thought that since i use await in my reduce, the callback should return the actual value instead of a promise:

const results = await fn(finalResult);

My code works fine if i take out the synchronous methods from my array. But I need to reduce an array of both synchronous and asynchronous methods. Does anyone have tips on how I can get around this? My full code is below.

const formatName = (person) => {
    person.name = person.name.toUpperCase();
    return person;
}

const formatAge = (person) => {
    person.age += 10;
    return person;
}

// Async function  
const formatLocation = async (person) => {
    await new Promise(resolve => setTimeout(resolve, 1000));
    person.location = `${person.location.toLocaleLowerCase()}`
    return person;
}

const initialPerson = {
    name: "john",
    age: 35,
    location: 'USA'
}

const formattedStagesWithAsync = [
    formatLocation, // asynchronous
    formatAge, // synchronous
    formatName //synchronous
];

const process = async () => {
    const formattedPerson = await formattedStagesWithAsync.reduce(async (finalResult, fn) => {
        const results = await fn(finalResult);
        return results;
      }, initialPerson);

    console.log(`Formatted person - ${JSON.stringify(formattedPerson, null, 2)}`);
}   

process();
1

2 Answers 2

2

Async functions always return promises, so on subsequent iterations of the .reduce callback, the accumulator will be a Promise that you need to wait to resolve first.

While you could do

const accumVal = await finalResult

at the beginning of the callback, this would be a lot simpler by avoiding reduce entirely IMO.

const process = async () => {
  let person = initialPerson;
  for (const fn of formattedStagesWithAsync) {
    person = await fn(person);
  }

In the case that each of your functions returns the original object, like in the case here, that simplifies to:

const process = async () => {
  for (const fn of formattedStagesWithAsync) {
    await fn(initialPerson);
  }

(you're mutating the initialPerson in your original code too)

Sign up to request clarification or add additional context in comments.

Comments

-1

Promise return async value but dont use async and await option for Promise, Just return it

Promise docs

const promiseHandler = () => {
    return new Promise((done, reject) => {
        setTimeout(() => {
            done("hello");
        });
    });
}

promiseHandler().then(v => {
    console.log(v); // hello
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.