-1

I have a Node.js app. This app has a button that starts a process. The steps in that process return promises. I'm trying to chain these promises together. For some reason, I'm receiving an UnhandledPromiseRejectionWarning. However, in my mind, I've set this up correctly. My code looks like this:

var myButton = document.getElementById('myButton');
if (myButton) {
  console.log('here');
  myButton.addEventListener('click', executeAction('0'));
}

function executeAction(input) {      
  let param1 = 'A';
  let promise = new Promise(function(resolve, reject) {
    try {
      executeStep1()
        .then(result => executeStep2(param1, result, input))
        .then(result => function(result) {
           console.log('All done');
           resolve(result);
        })
        .catch(err => reject(err))
      ;
    } catch (ex) {
      reject(ex);
    }
  });
  return promise;     
}

function executeStep1() {
  let promise = new Promise(function(resolve, reject) {        
    try {
      setTimeout(function() {
        resolve('[something]');
      }, 3000);
    } catch (ex) {
      reject();
    }
  });
  return promise;
}

function executeStep2(p1, p2, p3) {
  let promise = new Promise(function(resolve, reject) {        
    try {
      setTimeout(function() {
        console.log('step 2 has executed');
        resolve('awesome!')
      }, 3000);
    } catch (ex) {
      reject(ex);
    }  
  });
  return promise;
}

I've confirmed that the executeStep2 function runs to completion. I'm basing this in the fact that I can see "step 2 has executed" in the console window. However, to my surprise, I never see "All done" printed in the console window. Instead, I see the UnhandledPromiseRejectionWarning mentioned above. I don't understand two things about this result:

  1. Why am I not seeing "All done" in the console? Shouldn't that function get executed after executeStep2 has resolved?
  2. Where is the rejection coming from? I don't see anything that's rejecting this.

Thank you very much for your help!

Some User
  • 5,257
  • 13
  • 51
  • 93
  • Remove `function(result)` in the second `then`. You are already using arrow function syntax there to declare the function. – Prakash Sharma Oct 17 '17 at 17:11
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it) anyway! Btw, you never need `try { … } catch(err) { reject(err) }` in a `new Promise` callback, the constructor does that automatically. – Bergi Oct 17 '17 at 17:27
  • What exactly is that `'[something]'` in your `executeStep2`, is that actually an expression that might throw an exception? – Bergi Oct 17 '17 at 17:29
  • 1
    Can you share your real code, please? `Button.addEventListener('click', executeAction('0'));` and `result => function(result) {` both look like mistakes – Bergi Oct 17 '17 at 17:32
  • If this is node, why are you accessing `document`? – zero298 Oct 17 '17 at 18:32
  • As Bergi said, post your **actual** code. I'm not seeing anything that will actually throw here. – zero298 Oct 17 '17 at 18:36

2 Answers2

0
executeStep1()
    .then(result => executeStep2(param1, result, input))
    .then(result => { // no function(result) here
       console.log('All done');
       resolve(result);
    })
    .catch(err => reject(err))
  ;
Prasanna
  • 4,125
  • 18
  • 41
  • 1
    This is closer. It no longer hangs when I run it. However, I still receive the `UnhandledPromiseRejectionWarning` error. – Some User Oct 17 '17 at 18:19
0

The error is generated from when you call the function(s) that uses promises:

myButton.addEventListener('click', executeAction('0'));

You need to catch rejections there also.

myButton.addEventListener('click', executeAction('0')
    .catch((error) => console.log('ERROR', error));

The rejections are caught inside the functions, but not in the outer scope because executeAction('0') returns a promise, or it would but you are using it as a non-async function, so its creating a promise and then returning a pending promise without waiting for it to be resolved. That looks like what's causing the rejection, and its also not handled for the above reason.

This will fix it:

function executeAction(input) {      
  let param1 = 'A';
  return new Promise(function(resolve, reject) {
    try {
      executeStep1()
        .then(result => executeStep2(param1, result, input))
        .then(result => function(result) {
           console.log('All done');
           resolve(result);
        })
        .catch(err => reject(err))
      ;
    } catch (ex) {
      reject(ex);
    }
  });
}

You should look into async/await. It can clean this code up significantly.

    async function getSomething() {
      try {
        // throw 'Test error detected.'
        return 'test'
      }
      catch (e) {
        throw e
      }
    }
    
    async function testing() {
      try {
        const sample = await getSomething()
        return sample
      } catch (e) {
        throw e
      }
    }
    
    testing()
      .then((data) => console.log(data))
      .catch((err) => console.log(err))

Run this above example, and then uncomment the throw. Use this pattern for maximum winning. Exceptions should be thrown to the surface level where the functions are called, displayed, used, rendered, etc. Functions should simply throw the error out.

This allows you to use error handling middleware, higher-order functions, listeners, logging, etc.

agm1984
  • 15,500
  • 6
  • 89
  • 113