20

I am using fetch to get data but it keeps returning promise as pending. I've seen many posts regarding this issue and tried all the possibilities but didn't solve my issue. I wanted to know why the fetch returns promise as pending in brief what are the possible cases where fetch returns pending status?

My piece of code for reference:

fetch(res.url).then(function(u){ 
    return u.json();
})
.then(function(j) { 
    console.log(j); 
});
VLAZ
  • 26,331
  • 9
  • 49
  • 67
Lahari
  • 461
  • 1
  • 3
  • 16
  • 5
    Why *wouldn't* it return a pending Promise? And why is it an issue? A fetch will issue a network request, it's non-blocking, hence async. – VLAZ Dec 18 '19 at 14:55
  • 1
    Sorry, which part is the promise pending? `console.log(j);` ? or something else? – TKoL Dec 18 '19 at 14:56
  • 3
    A promise will *always* be `pending` at first – Lux Dec 18 '19 at 14:58
  • 1
    It's async so it has to return a pending promise that you can then resolve/reject – voiys Dec 18 '19 at 14:58
  • 4
    Suppose you send me to the store to get some milk. Until I return with the milk, that job is pending. Upon my return, it is completed. It's the same with JS promises. You're sending a request to a remote server. Until that requested data is returned, is is pending. Once the data is back, it is completed. –  Dec 18 '19 at 14:59
  • When I'm printing the data in the console it keeps returning the same promise as pending. What does that mean? @voiys – Lahari Dec 18 '19 at 15:01
  • @SPL do you mean the `console.log(j)`? And are you *sure* it happens there? Because if you just do this in the console, the first thing that will print is the *return value of `fetch.then().then()`*. That return value is a Promise that is still pending at the time. – VLAZ Dec 18 '19 at 15:04
  • If you're printing data (I assume, `j`) in the console, the Promise is not pending, because you are inside the `then`, and you have data to log, so the call is finished. I don't understand the problem – Jeremy Thille Dec 18 '19 at 15:04
  • `console.log` isn't fed a promise, but an already resolved value. But if you do `fetch(url).then(doStuff).then(console.log)` in the console, then yes, the first thing you should see is `Promise {}`. That's expected and correct. – mbojko Dec 18 '19 at 15:05
  • Yeah I got that. It keeps loading and not entering the next _then_ .Is it the url fault? @VLAZ – Lahari Dec 18 '19 at 15:08
  • And what is going on in the Network tab? – mbojko Dec 18 '19 at 15:10
  • @SPL maybe? Are there any errors/warnings? CORS? – VLAZ Dec 18 '19 at 15:10
  • In my network it is showing as pending and I'm getting an error `Uncaught (in promise) SyntaxError: Unexpected token I in JSON` @VLAZ @mbojko – Lahari Dec 18 '19 at 15:12
  • Then what you get is *not* JSON, so `u.json()` throws that error. – VLAZ Dec 18 '19 at 15:13
  • That's the API. `fetch()` returns a Promise. `.json()` returns a Promise. The reason it returns a Promise is because that's the API. `XMLHttpRequest` deals in events and callbacks. If you want a different API, use a different function. – zero298 Dec 18 '19 at 15:37
  • user 47589: THAT is the way to answer a question as it explains it in everyday terms that "noobs" can also understand. Not everyone is a high brow web designer as some of SO respondents sometime believe (Some replies leave the user more baffled than when they started as the reply shows off the respondent`s technical prowess !) – Cristofayre Feb 12 '22 at 09:25

3 Answers3

16

As one of the upper comments said, fetch() is a promise that calls .then() when the request is handled by the network. The parameter in this callback is another promise that calls $.then() when we get the response from the server.

Maybe you should try something like this:

fetch(res.url)
    .then(function(serverPromise){ 
      serverPromise.json()
        .then(function(j) { 
          console.log(j); 
        })
        .catch(function(e){
          console.log(e);
        });
    })
    .catch(function(e){
        console.log(e);
      });

or in lambda notation:

fetch(res.url)
    .then((serverPromise) => 
      serverPromise.json()
        .then((j) => console.log(j))
        .catch((e) => console.log(e))
    })
    .catch((e) => console.log(e));

This is the first time I post here in StackOverflow, so please let me know if I made any mistake or you have any sugestions, thanks!

10

Promises are a way to allow callers do other work while waiting for result of the function.

See Promises and Using Promises on MDN:

A Promise is in one of these states:

  • pending: initial state, neither fulfilled nor rejected.
  • fulfilled: meaning that the operation completed successfully.
  • rejected: meaning that the operation failed.

The fetch(url) returns a Promise object. It allows attaching “listener” to it using .then(…) that can respond to result value (response to the request). The .then(…) returns again Promise object that will give result forward.

async and await

You can use JS syntax sugar for using Promises:

async function my_async_fn(url) {
    let response = await fetch(url);
    console.log(response); // Logs the response
    return response;
)

console.log(my_async_fn(url)); // Returns Promise

async functions return a Promise. await keyword wraps rest of the function in .then(…). Here is equivalent without await and async:

// This function also returns Promise
function my_async_fn(url) {
    return fetch(url).then(response => {
        console.log(response); // Logs the response
        return response;
    });
)

console.log(my_async_fn(url)); // Returns Promise

Again see article on Promises on MDN.

jiwopene
  • 3,077
  • 17
  • 30
9

A fetch() is a network operation. To avoid hanging until we get a reply from the network, we defer it to the background and give ourselves the promise that it will complete eventually.

So fetch(url).then((data) => data.json()) means that we fetch the url, wait for data to come in, get the json representation of the data and wait for that too (data.json() is a promise too)

Until we get a result, the promise is in the pending state. The server hasn't replied to our request yet.

-- Reading the comments, it might be nice to add a error handler as that is why the current fetch is supposedly not doing anything: fetch().then((data) => data.json()).catch((error) => console.log(error))

Jeffrey Devloo
  • 1,406
  • 1
  • 11
  • 20
  • 3
    or better switch to using async/await `async foo() { try { const res = await fetch(); const result = await res.json(); } catch (e) { console.log.error; } ); foo();` – gman Dec 18 '19 at 15:22
  • Also a possibility. Makes it more easy to read but OP was using `.then` chaining so I followed his example – Jeffrey Devloo Dec 18 '19 at 15:24
  • I wasn't critquing your answer. I was suggesting another solution to the questioner. I find async/await far eaiser to use than `.then` so I when I see I user struggling with `.then` I generally suggest switching to async/await. It's just easier overall IMO. – gman Dec 18 '19 at 15:26
  • I did not take it as a critique and I agree with your statement here too :) – Jeffrey Devloo Dec 18 '19 at 15:28
  • 2
    Your **(data.json() is a promise too)** save me a lot of time hahah I did not know that – Nico Serrano Jan 26 '22 at 03:53