4

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)
    }

charlietfl
  • 170,828
  • 13
  • 121
  • 150
user2547766
  • 111
  • 7
  • 1
    Using the new Promise when fetch() already returns a promise is an anti-pattern. See [What is the explicit promise construction antipattern and how do I avoid it?](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it) – charlietfl Jul 25 '20 at 19:19

3 Answers3

4

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.)

CherryDT
  • 25,571
  • 5
  • 49
  • 74
  • I'm yet to try your simplified version with async / await but your explanation regarding the "then" promise was spot on. – user2547766 Jul 25 '20 at 21:54
  • 1
    Just to add I've tried the async / await example now and it does the trick. This stuff is finally making sense - awesome :) – user2547766 Jul 25 '20 at 22:34
1

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.

vibhor vaish
  • 153
  • 1
  • 13
-2

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

Kyle DePace
  • 156
  • 7