JavaScript
Promises
Programming
Asynchronous
Code

Passing value into next Promises argument

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In a promise chain, the value for the next .then(...) callback comes from what the previous handler returns. You do not manually push a value into the next promise as a separate step. You either return a plain value, return another promise, or throw an error, and the chain updates itself accordingly.

The Core Rule Of .then()

A promise callback receives the previous fulfillment value. Its return value becomes the fulfillment value of the next link in the chain.

javascript
1Promise.resolve(5)
2  .then((value) => {
3    console.log("first:", value);
4    return value * 2;
5  })
6  .then((value) => {
7    console.log("second:", value);
8  });

Output:

text
first: 5
second: 10

The second .then(...) gets 10 because the first handler returned value * 2.

Returning A Plain Value Versus A Promise

If you return a plain value, the next promise resolves with that value.

javascript
Promise.resolve("hello")
  .then((value) => value.toUpperCase())
  .then((value) => console.log(value));

If you return a promise, the next step waits for that promise to resolve.

javascript
1function fetchUserName() {
2  return new Promise((resolve) => {
3    setTimeout(() => resolve("mark"), 100);
4  });
5}
6
7Promise.resolve()
8  .then(() => fetchUserName())
9  .then((name) => console.log(name));

This is why promise chains flatten automatically. You do not get a promise of a promise in normal .then(...) usage.

If You Need To Pass More Than One Value

A .then(...) callback only passes one fulfillment value forward, but that value can be an object or array.

javascript
1Promise.resolve(3)
2  .then((count) => {
3    return {
4      count,
5      doubled: count * 2,
6      message: "done"
7    };
8  })
9  .then((result) => {
10    console.log(result.count);
11    console.log(result.doubled);
12    console.log(result.message);
13  });

If you need multiple related values later in the chain, package them intentionally instead of relying on outer mutable variables.

A Common Mistake: Calling Instead Of Wrapping

People often write:

javascript
Promise.resolve(5)
  .then(console.log("value"));

That is wrong because console.log("value") runs immediately, and its return value is passed to .then(...) instead of a callback function.

Correct forms are:

javascript
Promise.resolve(5)
  .then((value) => console.log(value));

or, if you only need the same function reference:

javascript
Promise.resolve(5)
  .then(console.log);

The same rule applies when you want to pass an extra value into the next handler. Wrap it in a function and return what the next step should receive.

Passing A Custom Value To The Next Step

Suppose the first async operation returns data you do not want to forward directly. Return the transformed value you actually want the next handler to receive.

javascript
1function getUser() {
2  return Promise.resolve({ id: 7, name: "Ava" });
3}
4
5getUser()
6  .then((user) => user.id)
7  .then((id) => {
8    console.log("next handler got:", id);
9  });

If you want both the original user and a derived value later, return both in one object.

javascript
1getUser()
2  .then((user) => {
3    return {
4      user,
5      isAdmin: user.id === 1
6    };
7  })
8  .then((result) => {
9    console.log(result.user.name);
10    console.log(result.isAdmin);
11  });

Error Flow Works The Same Way

If a handler throws, the chain becomes rejected and control moves to the nearest rejection handler.

javascript
1Promise.resolve(5)
2  .then((value) => {
3    if (value < 10) {
4      throw new Error("too small");
5    }
6    return value;
7  })
8  .then((value) => console.log(value))
9  .catch((error) => console.error(error.message));

Understanding this is important because success values are passed by return, while errors are passed by throw or by returning a rejected promise.

The Async/Await Equivalent

If promise chaining feels noisy, async and await express the same flow more directly:

javascript
1async function main() {
2  const user = await getUser();
3  const result = {
4    user,
5    isAdmin: user.id === 1
6  };
7  console.log(result);
8}
9
10main();

This does not change the underlying rule. The next step still gets whatever value you produce from the previous one. await just makes the control flow easier to read.

Common Pitfalls

  • Forgetting to return a value from a .then(...) callback and accidentally passing undefined forward.
  • Calling a function immediately instead of passing a callback function into .then(...).
  • Using outer mutable variables when returning an object or array would be clearer.
  • Returning a promise but also nesting another .then(...) unnecessarily.
  • Mixing rejection handling between the second argument of .then(...) and .catch(...) in a confusing way.

Summary

  • The next .then(...) receives whatever the previous handler returns.
  • Return a plain value to pass a value forward.
  • Return a promise to make the chain wait for another async result.
  • If you need multiple values later, return an object or array.
  • If you forget to return, the next step receives undefined.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.