1

The problem is like this

function demo() {
    return new Promise((resolve, reject) => {
        ...
        // The problem here!!
        //I just found in some rare case we failed to call resolve or reject
    })
}

demo()
    .then(res => {
        console.log('resolve')
        console.log(res)
    })
    .catch(rej => {
        console.log('reject')
        console.log(rej)
    })
    .finally(() => {
        console.log('why')
    })

When I failed to call resolve or reject, even the finally block is not called! Why ?

I had thought it was a bug then I found the original author seemed to do that on purpose that if he did not call either resolve or reject, none of then/catch/finally should be called, i.e. in that case no follow-up action should be taken.

But is this a valid way to handle the situation that no follow-up action should be taken ? Will it cause any trouble ?

----- update -----

Even though my question was marked duplicated I am still not satisfied with the answers I got. Originally I had thought it was a bad idea to let promise stay in pending state forever.

But the answer in that SO said "There should be no side effect."
Does never resolved promise cause memory leak? also said "In short - at least in modern browsers - you don't have to worry about unresolved promises as long as you don't have external references to them". So it seems ok to let promise stay in pending if that is the purpose.

Qiulang
  • 10,295
  • 11
  • 80
  • 129
  • 2
    Yes, that's as expected - if neither `resolve` nor `reject` are called, the Promise has no idea that the asynchronous action has completed, so none of the handlers attach to the Promise run. But promises that hang forever are a bad idea - best to fix the code so that it does eventually resolve or reject – CertainPerformance Apr 26 '19 at 06:32
  • So "is this a valid way to handle the situation that no follow-up action should be taken ? Will it cause any trouble? " – Qiulang Apr 26 '19 at 06:33
  • 1
    I don't think so, because it would be confusing to consumers of `demo` if neither a `then` nor a `catch` are ever called. Better to resolve (or reject) to something that contains information indicating that nothing further should be done, I think, eg `resolve('No action needed')` – CertainPerformance Apr 26 '19 at 06:35
  • So is there a way to reclaim those hanging promises ? – Qiulang Apr 26 '19 at 06:35
  • 1
    Only by fixing the function that returns the Promise - you'd have to refactor `demo` – CertainPerformance Apr 26 '19 at 06:36
  • There's no straightforward way. See for example https://stackoverflow.com/questions/39273680/view-all-pending-promises-in-javascript . Preferably don't use `new Promise` at all. Even if you have to, reject on timeout to prevent pending promises. – Estus Flask Apr 26 '19 at 06:46
  • 1
    What is `demo` actually doing? I can't imagine a scenario where not resolving a Promise makes sense. – Jonas Wilms Apr 26 '19 at 07:13
  • `I just found in some rare case we failed to call resolve or reject` then, quite simply, you're *doing it wrong™* – Jaromanda X Apr 26 '19 at 07:15
  • As I said in my question my first reaction was that was a bug, then I found the original author did that on purpose (in a wrong way apparently). Hence the question. – Qiulang Apr 26 '19 at 07:39
  • @Qiulang What do you mean by "reclaim"? They are [garbage-collected normally](https://stackoverflow.com/q/20068467/1048572). – Bergi Apr 26 '19 at 08:57
  • @Bergi thanks for that SO, but that question was "Are JavaScript forever-pending promises bad?" and the accepted answer is "There should be no side effect." Does that mean is NOT bad per se ? And more related to my question, "is this a valid way to handle the situation that no follow-up action should be taken". I had thought the answer is NO. But when you said my question was duplicated, were you suggesting the answer is not NO ? I was confused now. – Qiulang Apr 26 '19 at 09:37
  • 1
    @Qiulang It works (as you've seen, nothing happens), but I would still consider it a bad practice: it goes against most expectations, like `finally` never happening. It's as bad a non-terminating loop. – Bergi Apr 26 '19 at 11:47
  • @Bergi thanks for the confirmation. BTW, I really don't think my question is duplicated with one you mentioned. Mine is more about the proper way to handle the "no following up action". – Qiulang Apr 26 '19 at 12:37
  • @Qiulang If you absolutely want no follow-up action, then never settling the promise is the way. The bad practice is that you rarely, if ever, should prevent follow-up actions. What is your use case? – Bergi Apr 26 '19 at 12:46
  • @Bergi I further examined the code and realized the author did that b/c the calling function's then/finally block did not handle a situation. And because that then/finally block had been used (copy&paste) in many places, so instead of fixing it in each place, he added a fix in the place that returns promise with pending state, so the old then/finally block does not need to handle it. – Qiulang Apr 28 '19 at 03:17

3 Answers3

1

Internally, a promise can be in one of three states:

Pending, when the final value is not available yet. This is the only state that may transition to one of the other two states. Fulfilled, when and if the final value becomes available. A fulfillment value becomes permanently associated with the promise. This may be any value, including undefined. Rejected, if an error prevented the final value from being determined. A rejection reason becomes permanently associated with the promise. This may be any value, including undefined, though it is generally an Error object, like in exception handling.

https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Promise

In your case, the promise is in the pending state and calling demo function will always in wait for the promise status to be fulfilled or rejected.

Rajesh Verma
  • 309
  • 2
  • 8
  • I had thought "the calling done function will always in wait for the promise status to be fulfilled or rejected." But I found the calling done function actually continues to run instead of hanging there. – Qiulang Apr 26 '19 at 06:55
  • 1
    `calling done function` So, neither of you are dealing with promises, there is no *done* function ... `then`/`catch` and more recently `finally` - the latter two just being variations (sugar) of `.then` anyway – Jaromanda X Apr 26 '19 at 07:12
  • @JaromandaX I know there was no done function, what I mean was the calling function did not hang. – Qiulang Apr 26 '19 at 07:37
  • it was actually typo it is demo function in place of done – Rajesh Verma Apr 26 '19 at 10:48
  • @RajeshKrVerma thanks for answering but I can't make your answer the accepted one b/c I already knew what you said and I don't think "calling demo function will always in wait " – Qiulang Apr 26 '19 at 12:40
0

A promise is always expected to either resolve or reject. If you intend to do a no follow up, you may resolve with an empty dataset or reject with an error code that suits your use case.

0

You may use Promise.race to check if a promise was finished on time. So if you forgot to call resolve or reject into your promise, then Promise.race still be resolved or rejected after delay.

var promise1 = new Promise(function(resolve, reject) {
    setTimeout(reject, 500);
});

var promise2 = new Promise(function(resolve, reject) {

});

Promise.race([promise1, promise2]).then(function(value) {
  console.log(value);
}).catch(err => console.log('promise rejected'));
Andrei Belokopytov
  • 1,063
  • 7
  • 17