0

I am trying to figure out this for a long time now. I am trying to learn about how promises work and found this code in the article How do Promises Work? by Quil. I can see how sidePromise's dependencies are gonna be executed, its dependency being squareAreaAbstraction()

But how does squareAreaPromise execute its dependencies? I mean, we are calling the fulfil(sidePromise,10) explicitly, but where does fulfil() function for squareAreaPromise get called to fulfil its dependencies?

var squareAreaAbstraction = function(side) {
  var result = createPromise();
  fulfil(result, side * side);
  return result;
};
var printAbstraction = function(squareArea) {
  var result = createPromise();
  fulfil(result, console.log(squareArea));
  return result;
}

var sidePromise = createPromise();
var squareAreaPromise = depend(sidePromise, squareAreaAbstraction);
var printPromise = depend(squareAreaPromise, printAbstraction);

fulfil(sidePromise, 10);

function createPromise() {
  return {
    // A promise starts containing no value,
    value: null,
    // with a "pending" state, so it can be fulfilled later,
    state: "pending",
    // and it has no dependencies yet.
    dependencies: []
  };
}

function depend(promise, expression) {
  // We need to return a promise that will contain the value of
  // the expression, when we're able to compute the expression
  var result = createPromise();

  // If we can't execute the expression yet, put it in the list of
  // dependencies for the future value
  if (promise.state === "pending") {
    promise.dependencies.push(function(value) {
      // We're interested in the eventual value of the expression
      // so we can put that value in our result promise.
      depend(expression(value), function(newValue) {
        fulfil(result, newValue);
        // We return an empty promise because `depend` requires one promise
        return createPromise();
      })
    });

    // Otherwise just execute the expression, we've got the value
    // to plug in ready!
  } else {
    depend(expression(promise.value), function(newValue) {
      fulfil(result, newValue);
      // We return an empty promise because `depend` requires one promise
      return createPromise();
    })
  }

  return result;
}

function fulfil(promise, value) {
  if (promise.state !== "pending") {
    throw new Error("Trying to fulfil an already fulfilled promise!");
  } else {
    promise.state = "fulfilled";
    promise.value = value;
    // Dependencies may add other dependencies to this promise, so we
    // need to clean up the dependency list and copy it so our
    // iteration isn't affected by that.
    var dependencies = promise.dependencies;
    promise.dependencies = [];
    dependencies.forEach(function(expression) {
      expression(value);
    });
  }
}

I have tried running and debugging in VS code for over a day but I get lost in the depend() function

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • "*found this code in an article*" - please link the article and cite the title and author – Bergi Jul 08 '23 at 15:48
  • https://robotlolita.me/articles/2015/how-do-promises-work/ this is the article, i am not really sure who the author is – Saurav Singh Jul 08 '23 at 16:00
  • Thanks. [Their "about" page](https://robotlolita.me/about/) identifies the blogger as Quil, but the link itself is more important – Bergi Jul 08 '23 at 16:07

2 Answers2

0

This is due to this part of the code:

    promise.dependencies.push(function(value) {
      // We're interested in the eventual value of the expression
      // so we can put that value in our result promise.
      depend(expression(value), function(newValue) {
        fulfil(result, newValue);
        // We return an empty promise because `depend` requires one promise
        return createPromise();
      })
    });

When you do

var printPromise = depend(squareAreaPromise, printAbstraction);

expression is the function printAbstraction. So it adds a dependency that will call printAbstraction(value). WHen you fulfill squareAreaPromise() it executes all its dependencies, and this calls that function.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • thanks for the response, though i am having trouble understanding " when you fulfill squareAreaPromise() .. , how is the fulfil(squareAreaPromise, value) gonna be called? We are explicitly calling fulfil(sidePromise, 10) but I don't understand the part through where squareAreaPromise will be passed in fulfil() function I get the concept of depend(), but not the code walkthrough – Saurav Singh Jul 08 '23 at 19:22
  • That's what `expression(value)` does. `expression` contains the next function in the dependency chain. – Barmar Jul 08 '23 at 22:10
0

I can see how sidePromise's dependencies are gonna be executed, its dependency being squareAreaAbstraction()

No, it's not. Look at what exactly depend does put in the dependencies array:

function(value) {
  // We're interested in the eventual value of the expression
  // so we can put that value in our result promise.
  depend(expression(value), function(newValue) {
    fulfil(result, newValue);
    // We return an empty promise because `depend` requires one promise
    return createPromise();
  })
});

Here, expression is squareAreaAbstraction and result is the squareAreaPromise. So this is calling squareAreaAbstraction with sidePromise's value (squareAreaAbstraction(10)), and since that returns another promise, we call depend again to finally fulfill(squareAreaPromise, newValue) when that promise fulfills with newValue (which will be 100).

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I am having trouble exactly at the squareAreaPromise part I follow that expression is squareAreaAbstraction, but when its called with sidePromise's value, it returns a Promise object from squareAreaAbstraction, but why is that returned promise considered squareAreaPromise? Doesn't it just return a Promise object with updated value and state: fulfilled, but an empty dependencies array? I apologize if I missed something trivial – Saurav Singh Jul 08 '23 at 18:55
  • No, too many promises are named `result` here, which is confusing. The one I referred to was the one created and returned by `depend(…)` itself (and then assigned to `squareAreaPromise`). There's also the one created and returned by `squareAreaAbstraction(…)` when it is called with the result of `sidePromise`. To make it even more confusing, the former is going to be fulfilled with the result of the latter (so they both resolve to `100`), which is what `depend` is all about… – Bergi Jul 08 '23 at 21:07
  • thank you, everything makes sense now Would I be correct in assuming that closures play a big role in 'result' returned by depend() function? – Saurav Singh Jul 08 '23 at 22:04
  • Yes, [promises don't work without callbacks](https://stackoverflow.com/a/22562045/1048572), and closures are key – Bergi Jul 09 '23 at 03:08
  • thanks a ton, i have understood most of the code reworking all night, have a last bit of doubt left Why don't we directly call fulfill in the code you pasted above? Why do we have to wrap fulfill(result, newValue) inside depend() when we know that expression(value) will anyway return an object with fulfilled state? I hope I make sense – Saurav Singh Jul 09 '23 at 03:17
  • `expression(value)` should always return a promise, but it will not necessary always be a fulfilled one - that only happens in this particular example. Chaining multiple asynchronous actions sequentially is what makes promises so interesting - see the answer I linked in my previous comment. Consider putting the `fulfil(result, side * side);` in a timeout for a better example. – Bergi Jul 09 '23 at 03:19
  • can't thank you enough, I have been sleep deprived for the past 3 days because of this Have a good one ahead – Saurav Singh Jul 09 '23 at 03:33