admin管理员组

文章数量:1404335

Here's a subset of lots more code; JavaScript in Node.js. In essence, the equivalent to function a calls for some unit testing (in function b). On return from b, a calls for exception testing (in function c). c calls for synchronous exception testing (in function d). Later, c will call another function (e, say) for asynchronous exception testing (Promise reject() usage). It seems best to use Promises everywhere in Node.js, but even using them doesn't always result in behavior I predict.

'use strict';

function d() {
  return new Promise(function(resolve, reject) {
    console.log('start d   throw test');
    try {
      throw new Error('Error type');
    } catch (e) {
      console.log('d catch block   e.message=' + e.message +
        '   rejecting   to c');
      return reject(new Error('d   ' + e.message));
    } // catch
  }) // Promise
}

function c() {
  return new Promise(function(resolve, reject) {
    console.log('start c');
    d()
    .then( // d then
      function(result) { console.log('c   d result callback'); },
      function(error) {
        console.log('c   d error callback   error.message=' + error.message +
          '   rejecting   to a');
        return reject(new Error('second try'));
      }
    ) // d then
  }) // Promise
}

function b() {
  console.log('start b   resolving   to a');
  return Promise.resolve();
}

function a() {
  return new Promise(function(resolve, reject) {
    console.log('start a');
    b()
    .then( // b then
      function(result) {
        console.log('a   b result callback   to c');
        c();
      },
      function(error) { 
        console.log('a   b error callback   error.message=' + error.message);
      }
    ) // b then
    .then( // c then
      function(result) { 
        console.log('a   c result callback   ');
      },
      function(error) {
        console.log('a   c error callback   error.message=' + error.message);
      }
    ) // c then
    .catch(
      function(error) {
        console.log('a   final catch   error.message=' + error.message);
      }
    ) // catch
  }) // Promise
}

a();

I predicted, for example that every time I issue a Promise reject(), processing would occur in the caller's error callback. (Note that each reject() also uses new Error.) Hence, I expected this output in console.log.

start a
start b   resolving   to a
a   b result callback   to c
start c
start d   throw test
d catch block   e.message=Error type   rejecting   to c
c   d error callback   error.message=d   Error type   rejecting   to a
a   c error callback   error.message=second try

Note that when d called reject(), I predicted processing would go to the c error callback. Similarly, a c reject() would go to the a error callback. Instead, I'm getting this output:

start a
start b   resolving   to a
a   b result callback   to c
start c
start d   throw test
d catch block   e.message=Error type   rejecting   to c
c   d error callback   error.message=d   Error type   rejecting   to a
a   c result callback

The c reject() seems to be going to the a result callback.

Function b may be involved; if I write it out of the program, I get the desired processing. That's great for here, but in the larger code, it is no option.

Questions:

  1. Why is processing going to the result callback rather than to the error callback?
  2. How does function b cause effect so long after it's done?
  3. How can I fix this?
  4. What pluses and minuses are tied to using return reject versus reject alone? Most of the time (at least), it seems to work. I haven't caught the shorter form causing problems.

Here's a subset of lots more code; JavaScript in Node.js. In essence, the equivalent to function a calls for some unit testing (in function b). On return from b, a calls for exception testing (in function c). c calls for synchronous exception testing (in function d). Later, c will call another function (e, say) for asynchronous exception testing (Promise reject() usage). It seems best to use Promises everywhere in Node.js, but even using them doesn't always result in behavior I predict.

'use strict';

function d() {
  return new Promise(function(resolve, reject) {
    console.log('start d   throw test');
    try {
      throw new Error('Error type');
    } catch (e) {
      console.log('d catch block   e.message=' + e.message +
        '   rejecting   to c');
      return reject(new Error('d   ' + e.message));
    } // catch
  }) // Promise
}

function c() {
  return new Promise(function(resolve, reject) {
    console.log('start c');
    d()
    .then( // d then
      function(result) { console.log('c   d result callback'); },
      function(error) {
        console.log('c   d error callback   error.message=' + error.message +
          '   rejecting   to a');
        return reject(new Error('second try'));
      }
    ) // d then
  }) // Promise
}

function b() {
  console.log('start b   resolving   to a');
  return Promise.resolve();
}

function a() {
  return new Promise(function(resolve, reject) {
    console.log('start a');
    b()
    .then( // b then
      function(result) {
        console.log('a   b result callback   to c');
        c();
      },
      function(error) { 
        console.log('a   b error callback   error.message=' + error.message);
      }
    ) // b then
    .then( // c then
      function(result) { 
        console.log('a   c result callback   ');
      },
      function(error) {
        console.log('a   c error callback   error.message=' + error.message);
      }
    ) // c then
    .catch(
      function(error) {
        console.log('a   final catch   error.message=' + error.message);
      }
    ) // catch
  }) // Promise
}

a();

I predicted, for example that every time I issue a Promise reject(), processing would occur in the caller's error callback. (Note that each reject() also uses new Error.) Hence, I expected this output in console.log.

start a
start b   resolving   to a
a   b result callback   to c
start c
start d   throw test
d catch block   e.message=Error type   rejecting   to c
c   d error callback   error.message=d   Error type   rejecting   to a
a   c error callback   error.message=second try

Note that when d called reject(), I predicted processing would go to the c error callback. Similarly, a c reject() would go to the a error callback. Instead, I'm getting this output:

start a
start b   resolving   to a
a   b result callback   to c
start c
start d   throw test
d catch block   e.message=Error type   rejecting   to c
c   d error callback   error.message=d   Error type   rejecting   to a
a   c result callback

The c reject() seems to be going to the a result callback.

Function b may be involved; if I write it out of the program, I get the desired processing. That's great for here, but in the larger code, it is no option.

Questions:

  1. Why is processing going to the result callback rather than to the error callback?
  2. How does function b cause effect so long after it's done?
  3. How can I fix this?
  4. What pluses and minuses are tied to using return reject versus reject alone? Most of the time (at least), it seems to work. I haven't caught the shorter form causing problems.
Share Improve this question edited Jan 25, 2016 at 3:54 BaldEagle asked Jan 25, 2016 at 3:40 BaldEagleBaldEagle 1,02812 silver badges19 bronze badges 3
  • 1 it must be return c(); – mido Commented Jan 25, 2016 at 3:47
  • A very interesting read: pouchdb./2015/05/18/we-have-a-problem-with-promises.html You did the Rookie mistake #5, you didn't return c(). Also, don't mix things so much, either use error callback or (re)throw errors (throw is much advised), not both, it's confusing. – Shanoor Commented Jan 25, 2016 at 6:29
  • @ShanShan: Thanks for motivating me to reread that article. It is among the best of the articles on Promises I've seen. I didn't fully grasp Rookie mistake #5 before (obviously). – BaldEagle Commented Jan 27, 2016 at 19:44
Add a ment  | 

1 Answer 1

Reset to default 6

basic issue is, you did c(); instead of return c();, other issues include:

  • method d, c can be simplified, stop wrapping promises with new Promise(...)
  • avoid usage of .then(success, error), most cases, saner to use then(success).catch(error).
  • you code can be reduced to below:

    'use strict';
    
    function d() {
      return Promise.reject(new Error('Error type'));
    }
    
    function c() {
      console.log('start c');
      return d()
        .then( result => console.log('c   d result callback'))
        .catch( error => {
          console.log('c   d error callback   error.message=' + error.message +
            '   rejecting   to a');
          throw new Error('second try');
        });
    }
    
    function b() {
      console.log('start b   resolving   to a');
      return Promise.resolve();
    }
    
    function a() {
        console.log('start a');
      return b()
        .then(result => {
          console.log('a   b result callback   to c');
          return c();      
        }).catch(error => console.log('a   b error callback   error.message=' + error.message))
        .then(result => console.log('a   c result callback   '))
        .catch(error => console.log('a   final catch   error.message=' + error.message));
    }
    
    a();
    

本文标签: nodejsWhy does this JavaScript Promise reject() get processed at the result callbackStack Overflow