Console log from earlier promise appears after console log from latest promise

Viewed 87

The below isn't my exact code but I just wanted to outline the structure. When I run the code the sequence I get the console logs is this:

  1. 'Done'
  2. json

I was expecting this to be the other way round because in order for function2 to complete (and send the 'Done' resolve value), function3 would have to finish first.

I'd like to understand why it doesn't work that way.

function1().then(() => {
      return function2()
    ).then((message) => {
      console.log(message)
    })

    function function2() {
      return new Promise((resolve, reject) => {
        fetch(url, {
            method: 'get',
            body: null,
            headers: {
              "Content-Type": "application/json; charset=UTF-8",
              "Accept": "application/json; charset=UTF-8",

            },
          })
          .then(res => res.json())
          .then((json) => {
            return function3(json)
          })

        resolve('Done')
      })
    }

    function function3(json) {
      console.log(json)
    }

3 Answers

You are calling resolve before your fetch is even done.

It would work if you'd move it into another then:

// ...
.then(res => res.json())
.then((json) => {
    return function3(json)
})
.then(() => {
    resolve('Done')
})

But in fact, the whole new Promise thing isn't even necessary because fetch already returns a promise!

// ...

function function2() {
    return fetch(url, { // It's important to actually *return* the promise here!
        method: 'get',
        body: null,
        headers: {
            "Content-Type": "application/json; charset=UTF-8",
            "Accept": "application/json; charset=UTF-8"
        }
    })
    .then(res => res.json())
    .then((json) => {
        return function3(json)
    })
    .then(() => {
        return 'Done'
    })
}

This could be further simplified using async/await:

// I moved this into a function because the global module-level code
// is not in an async context and hence can't use `await`.
async function main () {
  await function1()
  console.log(await function2())
}

async function function1 () {
  // I don't know what this does, you didn't include it in your code snippet
}

async function function2 () {
  const response = await fetch(url, {
    method: 'get',
    body: null,
    headers: {
      "Accept": "application/json; charset=UTF-8"
    }
  })
  
  const json = await response.json()
  await function3(json)

  return 'Done'
}

// At the moment this wouldn't have to be async because you don't do anything
// asynchronous inside, but you had `return function3(json)` in the original code,
// so I assume it is *going* to be async later.
async function function3 (json) {
  console.log(json)
}

// Don't forget to .catch any rejections here! Unhandled rejections are a pain!
main().catch(console.error)

(While I was at it, I removed the Content-Type header, since it has no meaning for a GET request anyway.)

You have missed the fact that fetch works asynchronously and gets loaded to callback queue while resolve here works in a synchronous manner. So even if fetch were to finish before resolve , it would still execute after resolve due to javascript loop. You need to chain resolve in the further then chains of fetch to achieve the desired functionality.

In function 2, fetch is called, and only the .then() chain is paused. The next javascript to be read is resolve() which resolves the promise. A few seconds later the promise resolves and continues down the chain to function 3 where 'Done' is logged

Related