Chaining Promises in native Javascript

Raychaser

I want to chain 3 promises together but there's some behaviour I can't figure out regarding the resolve and reject functionality. I've simplified my code in order to ask the question:

function testP(num) {
  return new Promise((resolve, reject) => {
    console.log('Do Work', num);
    reject(num);
  });
}

function testPromises() {
  return new Promise((resolve, reject) => {
      testP(1)
        .then(testP(2))
        .then(testP(3))
        .then(resolve)
        .catch(reject);
  });
};

const theTest = testPromises().then(()=>{
    console.log("all done");
}).catch(err => {
    console.log("ERR", err);
});

And what I'm seeing in my output is:

Do Work 1
Do Work 2
Do Work 3
ERR 1

Why does the code get to Do Work 2 and Do Work 3 if the first promise hits reject immediately? My understanding was that the then functions wait for the promise to resolve or reject before executing.

T.J. Crowder

Because when you do

.then(testP(2))

you call testP immediately and unconditionally, passing in 2, and then pass its return value into .then, exactly the way foo(bar()) calls bar and passes its return value into foo.

This code:

  testP(1)
    .then(testP(2))
    .then(testP(3))
    .then(resolve)
    .catch(reject);

is evaluated like this (some minor details omitted):

  • Call testP with the value 1 and remember the resulting value as p1
  • Call testP with the value 2
  • Call p1.then with the result of that call and remember the resulting value as P2
  • Call testP with the value 3
  • Call p2.then with the result of that call and remember the resulting value as p3
  • Call p3.then with the value resolve and remember the result as p4
  • Call p4.catch with the value reject
  • Call the reject function from the first call to testP with the value 1
  • Call the reject from testPromises with the value 1

If you want that testP to wait until the first one is settled, you don't call it, you pass a reference to it:

.then(testP)

If you want it to have an argument baked in, use bind:

.then(testP.bind(null, 2))

or an inline function:

.then(function() {
    return testP(2);
 })

Example (requires a browser with Promise):

function testP(num) {
  return new Promise((resolve, reject) => {
    console.log('Do Work', num);
    reject(num);
  });
}

function testPromises() {
  return new Promise((resolve, reject) => {
      testP(1)
        .then(testP.bind(null, 2))
        .then(testP.bind(null, 3))
        .then(resolve)
        .catch(reject);
  });
};

const theTest = testPromises().then(()=>{
    console.log("all done");
}).catch(err => {
    console.log("ERR", err);
});

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related