Java Promises hell/chaining promises in Javascript

  • Thread starter Thread starter shivajikobardan
  • Start date Start date
  • Tags Tags
    Javascript
AI Thread Summary
The discussion focuses on converting callback hell in JavaScript to a promise-based approach, emphasizing the importance of controlling the execution flow. The initial code fails because it executes all promises simultaneously, leading to incorrect order of operations, while the corrected version uses nested promises to ensure each step waits for the previous one to complete. The participants explore the asynchronous nature of JavaScript, noting that while promises return immediately, their resolution happens based on the timers set. The conversation highlights the confusion surrounding asynchronous programming and the necessity of understanding how promises work to achieve the desired sequence of events. Ultimately, the goal is to clarify the mechanics of promises to improve asynchronous code management.
shivajikobardan
Messages
637
Reaction score
54
TL;DR Summary
asynchronous javascript
https://www.physicsforums.com/threa...-as-well-as-async-await.1048282/#post-6833326
My goal is to convert the callback hell in question to using promises.

The correct flow of program is:
Order created
Order received
Preparing food
Order ready
order delivered

The below code is wrong. If you put 9000 instead of 1000, the flow isn't correct.
JavaScript:
function createorder(timer = 0) {
  return new Promise(function (resolve) {
    setTimeout(resolve, timer);
  });
}

createorder(1000).then(() => {
      console.log('Order Created');
});

createorder(2000).then(() => {
      console.log('Order Received');
});

createorder(3000).then(() => {
  console.log('Preparing Food');
});

createorder(4000).then(() => {
  console.log('Order Ready');
});

createorder(5000).then(() => {
  console.log('Order Delivered');
});

But I fail to understand why it's wrong. Let's do a dry run of it:

Assume 9000 instead of 1000.

Wait 9s till the promise is resolved then "order created" gets printed.
Wait 2s till the promise is resolved then "order received" gets printed.
Wait 3s till the promise is resolved then "preparing food" gets printed.
Wait 4s till the promise is resolved then "order ready" gets printed.
Wait 5s till the promise is resolved then "order ready" gets printed.
I did it using promises hell and it's correct
JavaScript:
function createOrder(timer)
{
  return new Promise(function(resolve,reject){
    setTimeout(resolve,timer);
  })
}
createOrder(9000).then(function(){
  console.log("Order created");
  createOrder(1000).then(function(){
    console.log("order received");
    createOrder(1000).then(function(){
      console.log("preparing food");
      createOrder(1000).then(function(){
        console.log("order ready");
        createOrder(1000).then(function(){
          console.log("order delivered");
        })
      })
    })
  })
})

Dry run:

1) Wait 9s till promise is resolved, then print "order created".
then
2) Wait 1s till promise is resolved, then print "order received".
then
3) Wait 1s till promise is resolved, then print "preparing food".
then
4) Wait 1s till promise is resolved, then print "order ready".
then
5) Wait 1s till promise is resolved, then print "order delivered".
I must say I kinda get why this works (The "then".."then".."then".."then" makes it clear). But I don't understand why the first code block doesn't work.
I'm really finding it tough asynchronous javascript. I'm really out of ideas, and only a good analogy to learn can save me now.
 
Technology news on Phys.org
PS the code copying feature doesn't seem to work in PF.
1671543008502.png
 
shivajikobardan said:
Assume 9000 instead of 1000.

Wait 9s till the promise is resolved then "order created" gets printed.
Wait 2s till the promise is resolved then "order received" gets printed.
Wait 3s till the promise is resolved then "preparing food" gets printed.
Wait 4s till the promise is resolved then "order ready" gets printed.
Wait 5s till the promise is resolved then "order ready" gets printed.
My thoughts, with no convenient way to verify them, is that these calls to createOrder() aren't happening synchronously -- while the timer is running for the "order created" call, the other calls are executing. If my logic is correct, you would see "order received", "preparing food", and then "order ready" either before or after "order created".
 
It's been, like, five years, which is five millennia in JavaScriptland but...

Doesn't nesting the promises defeat the whole purpose of asynch? The rationale of asynch the assumption that you can't count on any particular data arriving in time for other activities, If you force that, what's the point?
 
DaveC426913 said:
It's been, like, five years, which is five millennia in JavaScriptland but...

Doesn't nesting the promises defeat the whole purpose of asynch? The rationale of asynch the assumption that you can't count on any particular data arriving in time for other activities, If you force that, what's the point?
Interesting instructor also used similar wordings like yours. Could you explain a bit more?
 
shivajikobardan said:
Interesting instructor also used similar wordings like yours. Could you explain a bit more?
I remember having the same cognitive roadblock when learning: "Promises are The New Thing. Now, how do I cram them into my old, synchronous way of thinking?"

I think the question you need to ask yourself is: what are you trying to accomplish by using promises? Knowing that their very purpose is asynchrony, how are you using that to help your functionality?

At the risk of being glib, is it possible that you've been given a hammer and are concluding your app must be made of nails?I think we need to understand the parameters of the assignment before we can decide how to design it. For starters, is this a learning assignment or is it a real-world application?
 
Last edited:
shivajikobardan said:
I don't understand why the first code block doesn't work.
It does work since it does exactly what you ask for.

You create a promise and ask to wait for 9s and then write "order created";

Then the code jumps to the next line - while the first promise is working asynchronously - where you ask to wait for 2s and then write "order received";

Then the code jumps to the next line - while the first and second promises are working asynchronously - where you ask to wait for 3s and then write "preparing food";

Then the code jumps to the next line - while the first, second, and third promises are working asynchronously - where you ask to wait for 4s and then write "order ready";

Then the code jumps to the next line - while the first, second, third, and fourth promises are working asynchronously - where you ask to wait for 5s and then write "order delivered";

All of this is done really fast (in the order of milliseconds) and all your promises are working together. Of course, they will resolve according to the time you set, so the text with the shortest time will appear first and the one with the longest time will appear last.

In the second example, you ask to do the next step only after the previous promise is resolved (activating the "then" function). So for the code to find out about the next promise to execute, it has to wait for the signal of the "parent" promise.
 
shivajikobardan said:
TL;DR Summary: asynchronous javascript

The below code is wrong.
Yes. That's because each call to createOrder returns immediately. That's what an async function does; it returns immediately, as soon as you call it, and the thing it returns is a promise, i.e., an object that represents an action that hasn't been completed yet. Caling .then on the return value of createOrder then also returns immediately, since .then is another async function that returns a promise.

So your "dry run" for this case is wrong. Here's what actually happens:

Set a timer that will go off in 9 seconds, and immediately return a promise that represents it; then call .then on this promise, which sets up a print statement to happen when the timer goes off, and immediately return an updated promise that represents that.

Do the same with 4 more timers and 4 more corresponding print statements.

All of this will return, and control flow will be at the bottom of your code block, before the first timer goes off. So what is actually controlling the order in which the print statements execute is the timing on the timers, not the order in which you make the function calls. The timers all start at basically the same time (since the time it takes to execute all of your code and return promises is negligible, much less than a second), so their timeouts control the order in which the timers go off and the print statements execute. And indeed that's what you're seeing.

In your second example, you are instead using repeated calls to .then to control the order in which the print statements execute, as well as using the timers to control the delays between them. That's why your "dry run" is correct for this case.
 
DaveC426913 said:
Doesn't nesting the promises defeat the whole purpose of asynch?
No. What it does is allow you to control the order in which certain things happen, while still taking advantage of the fact that, while those things are happening, your code can be doing something else. The real "async" that allows all that is happening deep inside the runtime engine, not anywhere in your code. That's why async code is often hard to reason about: because you can't see the actual control flow that is happening down in the runtime engine, where it is keeping track of all the async tasks that haven't completed and what each one is waiting on.
 
  • Informative
  • Like
Likes pbuk, berkeman and DaveC426913
Back
Top