skip to Main Content

To start, I realize that I can use async/await or promise chains to accomplish this. I’m trying to understand why the following specifically doesn’t work.

My understanding of this code is that it should make the p1 fetch, which in turn sends the HTTP request to the event queue and immediately starts making the request async, run the for loop (blocking, code below won’t run until the for completes), then make the p2 fetch (by this time I would expect that the p1 fetch would be complete), then we get to the p1.then and the p2.then. Since I gave the p1 a huge head start in the form of the for loop, I would expect that we almost always would print 0. But that is not the case. It seems completely indeterministic. I understand that there are network conditions, but I would think that the head start given by the for loop would be enough to deterministically return 0.

This makes me feel like I have a gap in my understanding. I’m wondering why this works this way?

let x = 1;
let url = "https://www.google.com";

let p1 = fetch(url);

for (let i = 0; i < 1000000000; i++) {}

// Is it possible to ensure that the promise `p1` gets resolved earlier than `p2`? (By blocking the code here) Not working with the `for` loop.

let p2 = fetch(url);

p1.then(() => {
  x = 0;
});

p2.then(() => {
  x = x * 1;
  // Because of the race condition between `p1` and `p2`, the value of `x` is indeterministic.
  console.log(x);
});

I tried increasing the iterations of the for loop and still got an indeterministic result.

2

Answers


  1. If you want the operations in your two .then()s to be executed in a certain order you should use something like Promise.all() to enforce both promises to be fulfilled before the actual processing of the data will start in the predefined order:

    const url = "https://dummyjson.com/";
    
    let p1 = fetch(url+"users/3").then(r=>r.json());
    let p2 = fetch(url+"posts/7").then(r=>r.json());
    Promise.all([p1,p2]).then(([u,p])=>{
      console.log(`1. user with id ${u.id} is ${u.firstName} ${u.lastName}.`);
      console.log(`2. the post with id ${p.id} is`,p.title);
    });
    Login or Signup to reply.
  2. let x = 1;
    let url = "https://www.google.com";
    
    async function fetchSequentially() {
      let p1 = fetch(url);
      
      // Wait for p1 to resolve
      await p1;
    
      // Blocking code, but now `p1` is guaranteed to be resolved
      for (let i = 0; i < 1000000000; i++) {}
    
      let p2 = fetch(url);
      
      await p2;
      
      // Update x after both fetches are completed
      x = 0;
      console.log(x); // This will reliably print `0`
    }
    
    fetchSequentially();

    fetchSequentially ensures that p1 completes before p2 starts, and the blocking for loop occurs after p1 has been resolved. This way, you eliminate the race condition between p1 and p2

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search