Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default Unhandled Rejection Detection Behavior #830

Closed
benjamingr opened this issue Feb 13, 2015 · 135 comments
Closed

Default Unhandled Rejection Detection Behavior #830

benjamingr opened this issue Feb 13, 2015 · 135 comments
Labels

Comments

@benjamingr
Copy link
Member

@benjamingr benjamingr commented Feb 13, 2015

With #758 (hopefully) soon landing to address #256 we will soon have unhandled promise rejections reported to the process via a process.on("unhandledRejection" event.

One issue that was deliberately deferred from that issue and PR is what the default behaviour of an unhandled promise rejection detected be.

Just to be clear - this is about the default behaviour of a rejected promise with no catch handler (or then handler with a function second argument) attached.

The different approaches

  • Logging the rejection to the console.
  • Throwing an error for process.on("uncaughtException" to deal with.
  • Causing the process to exit.
  • Do nothing by default.

There are several good arguments for each approach. I'll write down the arguments I'm aware of and will edit arguments as people make them in comments.

Logging

  • No silent failure by default.
  • Does not break any existing code - no "surprises". (See comment by @vkurchatkin on this)
  • Been a default in several userland libraries like bluebird and users have been very satisfied with it.

Throwing an error

  • A promise rejection is the asynchronous version of a thrown exception.
  • Does not ignore logical errors or leave the app in an inconsistent state.
  • False positives are extremely rare - and code causing them can arguably easily be refactored to not cause them by not attaching error handlers too late.

Process Exit

  • Differentiation between uncaught exceptions and promise rejections might be useful.

Do nothing

  • Reliable promise rejection detection is non-deciable, it's possible to report an unhandled rejection that actually is handled at a later point if the catch handler is attached at a very late time.
  • Does not break any existing workflows for anyone. No backwards compatibility issues for native promise users at all.
  • Does not make any assumptions on how people use native promises.

What do people think the default behaviour should be?

@vkurchatkin
Copy link
Contributor

@vkurchatkin vkurchatkin commented Feb 13, 2015

Does not break any existing code - no "surprises".

Actually, logging to stdout (or stderr, I guess) can cause crash: nodejs/node-v0.x-archive#6612

@golyshevd
Copy link

@golyshevd golyshevd commented Feb 13, 2015

Logging

IMHO emitting some event it is already enough logging. Direct writing to console is dirty and inconvenient to use with custom loggers, it may violate a format of application logs.
Sometimes i think about some built-in flexible logging facility (log levels, handlers, formatters, etc.) like logging in python

Throwing an error

Much more transparent way. An exception which was caught with promise but was not handled should be thrown. But it is painful breaking behaviour. Developers should promise.then(fn).then(null, noop) to explicitly ignore exceptions

Causing the process to exit.

Does thrown error will not be caught by uncaughtException event handler? Is not is the same as previous approach?
Do I understand correctly that the difference is that in one case the exception will be sent directly in the uncaughtException event handler, and in the second case the exception will be rethrown, but will still be caught in the uncaughtException handler if specified?

Do nothing

As variant to give developers choose how to handle unhandled promise rejections

@Havvy
Copy link
Contributor

@Havvy Havvy commented Feb 13, 2015

Of those options, I'd argue for doing nothing. The end user can figure out what they'd like as a default, and add the handling there. If you want to be really strict about catching them, you can do process.on("unhandledRejection", function (err) { throw err; }). Personally, using Bluebird, I've only seen it once, and it was a false positive.

@benjamingr
Copy link
Member Author

@benjamingr benjamingr commented Feb 13, 2015

I'd just like to emphasise that this discussion is about defaults - all options will remain open to developers and they'll still be able to decide all this.

@Havvy Thanks for your thoughts - I find those statistics very different from what bluebird users have been reporting. False positives are very rare but true positives are extremely common when people have typos or pass invalid JSON around etc.

@golyshevd - just to be clear - are you for throwing or for no default?

@petkaantonov
Copy link
Contributor

@petkaantonov petkaantonov commented Feb 13, 2015

The problem with doing nothing is that the feature might as well not exist as it will be undiscoverable to most developers.

IMHO emitting some event it is already enough logging. Direct writing to console is dirty and inconvenient to use with custom loggers, it may violate a format of application logs.

This is exactly what the default uncaught exception handler does minus exiting the process....

@tellnes
Copy link
Member

@tellnes tellnes commented Feb 13, 2015

I would say emitting an event eg unhandledRejection and throw if there is no event handler. Similar to how uncaughtException works. Or maybe we could emit it as an uncaughtException if there is no handler for unhandledRejection.

At least, don't choose to do nothing. Errors which are silenced is a nightmare to debug.

@golyshevd
Copy link

@golyshevd golyshevd commented Feb 13, 2015

@benjamingr

@golyshevd - just to be clear - are you for throwing or for no default?

I am for no default as emitting event as @petkaantonov already implemented. It might be simply changed to throw like

process.on('unhandledRejection', function (err) {
    throw err;
});

process.on('uncaughtException', function (err) {
   log(err);
});
@aheckmann
Copy link
Contributor

@aheckmann aheckmann commented Feb 13, 2015

-1 for throwing bc not everyone agrees. we cannot break anyone's programs and this potentially would.

+1 for logging by default. as EventEmitter by default logs a message when the number of max listeners has been exceeded but supports overriding the default behavior through setMaxListeners etc, and as uncaughtException crashes the program by default yet supports overriding that behavior by setting a listener, we could log by default here and support overriding that behavior when a user sets an unhandledRejection listener.

+1 for documenting this at the top of the Promises page in iojs.com


Sent from Mailbox

On Fri, Feb 13, 2015 at 6:48 AM, Dmitry notifications@github.com wrote:

@benjamingr

@golyshevd - just to be clear - are you for throwing or for no default?
I am for no default as emitting event as @petkaantonov already implemented. It might be simply changed to throw like

process.on('unhandledRejection', function (err) {
    throw err;
});
process.on('uncaughtException', function (err) {
   log(err);
});

Reply to this email directly or view it on GitHub:
#830 (comment)

@meandmycode
Copy link

@meandmycode meandmycode commented Feb 13, 2015

+1 for throwing personally, but perhaps I'm not understanding the current support problem. If (native) promises are new- how are people using them to any degree yet? surely this has zero impact on promise libraries. If you decide to upgrade to native promises then you deal with the behavior change. Swallowing errors by default? seems like an unbelievable discussion for such a low level platform.

@Fishrock123 Fishrock123 added the discuss label Feb 13, 2015
@domenic
Copy link
Member

@domenic domenic commented Feb 13, 2015

To be clear to those thinking this is about swallowing errors "by default": not handling a promise error is the same as forgetting to check the err parameter passed to your callback, which of course we see happening all the time in the real world as well as in example code. The fact is that promises actually have a better story than callback-errors here, because since promises have two callbacks (one for fulfilled, one for rejected), we can detect if you didn't handle the error, and emit an event.

So promises swallow errors "by default" to the same extent callbacks do. This is about how we can be even better.

@domenic
Copy link
Member

@domenic domenic commented Feb 13, 2015

... and that actually leads to a good way of addressing the question posed in the OP.

Let's say you had a magic way of detecting if someone forgot to handle the err parameter to their callback, and instead just proceeded as normal---either on purpose or because of forgetfulness. Would you like io.js to use this magic power to log to the console when that happens? Crash your program? Do nothing?

The tradeoffs are very similar, so I hope your answer to that question can help you contextualize the question posed in the OP.

@benjamingr
Copy link
Member Author

@benjamingr benjamingr commented Feb 13, 2015

Let's say you had a magic way of detecting if someone forgot to handle the err parameter to their callback

Forgot to handle the err parameter and an actual scenario occurred where the err parameter was not null (that is, an error happened).

I like the comparison by the way.

@petkaantonov
Copy link
Contributor

@petkaantonov petkaantonov commented Feb 13, 2015

not handling a promise error is the same as forgetting to check the err parameter passed to your callback

It's not the same at all, callback errors are always/generally operational while promise rejections can be either programmer errors or operational errors.

@meandmycode
Copy link

@meandmycode meandmycode commented Feb 13, 2015

I disagree that unhandled promise rejection is like callback error, the error callback pattern makes it very hard to accidentally forget about the error happening, as its forced as part of callback flow, you either get what you wanted or an error, promises however break this apart (for the better), plus you are assuming that the callback pattern node has somehow proved the concept for how things should be. It works but its not an ideal.

Chrome is already dealing with this issue retroactively by now ensuring that unhandled rejections throw, the only reason the entire page doesn't get dismantled is because historically the default reaction to unhandled errors in browsers is to try and keep going.

@domenic
Copy link
Member

@domenic domenic commented Feb 13, 2015

Chrome is already dealing with this issue retroactively by now ensuring that unhandled rejections throw

This is inaccurate. Chrome logs; it does not throw.

@meandmycode
Copy link

@meandmycode meandmycode commented Feb 13, 2015

Ah, apologies on that detail- this seemed to be the original idea suggested from what I had last seen, but you are obviously deeper down the rabbit hole :).

Was the decision not to throw/onerror in Chrome related to how people had already started to use promises? presumably by not always chaining them correctly, ie that you may return a promise that is chained in the 'next tick' instead of the current?

If so, out of interest; were there any scenarios that meant you couldn't chain in the current tick?

@petkaantonov
Copy link
Contributor

@petkaantonov petkaantonov commented Feb 13, 2015

If so, out of interest; were there any scenarios that meant you couldn't chain in the current tick?

If you have a container that creates a promise that is meant to be used later then you cannot chain in the current tick. However that container should just do promise.catch(() => ) so that errors are not surfaced until the promise is chained from outside the container.

In other cases you may accidentally write such code but it can be always refactored.

@benjamingr
Copy link
Member Author

@benjamingr benjamingr commented Feb 17, 2015

@domenic can you link to the relevant parts of the streams spec that requires/needs attaching error handlers asynchronously?

@jonathanong
Copy link
Contributor

@jonathanong jonathanong commented Feb 18, 2015

i believe these are serious programmer errors, so it should kill the process or be passed to uncaughtException unless you change the default behavior. i'm not a big fan of logging because if you rely on stdout or stderr, it's noisy.

@petkaantonov
Copy link
Contributor

@petkaantonov petkaantonov commented Feb 18, 2015

i'm not a big fan of logging because if you rely on stdout or stderr, it's noisy.

Again, this is exactly what the default uncaughtException does minus exiting the process. Are you seriously suggesting that the default should be exiting the process without writing the stack to stderr? As a side note if your stderr is noisy you should really fix the errors :D

@jonathanong
Copy link
Contributor

@jonathanong jonathanong commented Feb 18, 2015

@petkaantonov i like my stderr silent. it's not noisy at all and i'd like to keep it that way :D

i guess a better way to pharse this is that i think these unhandled errors should be passed to uncaughtException, which (basically) console.error(err.stack); process.exit(1); unless there's a listener. in this specific instance, we can make it unhandledException to differentiate these errors.

i didn't explicitly say that it should console.error(err.stack); process.exit(1); but that's what i implied. not just process.exit(1) - that would be absolutely useless.

@Raynos
Copy link
Contributor

@Raynos Raynos commented Feb 27, 2015

I think one of the very useful features of uncaught exceptions is the --abort-on-uncaught-exception flag.

Having an --abort-on-unhandled-rejection flag will satisfy the most diehard "crash first" fanatics (like myself).

This means I get the most important thing I want, which is a core dump with the actual stack of the exception.

@benjamingr
Copy link
Member Author

@benjamingr benjamingr commented Feb 27, 2015

👍 for an --abort-on-unhandled-rejection flag. I like that idea.

@benjamingr
Copy link
Member Author

@benjamingr benjamingr commented Mar 8, 2015

I think we haven't really reached a consensus here - this has not generated enough interest given how new the feature is in my opinion.

Our options are:

  • Bring this up for a TC meeting which means that the TC decides on this default behaviour. Given how the discussion about the hooks themselves went it did not seem like multiple TC members had used the hooks or userland promises that provide similar hooks I do not think this is an optimal way to proceed.
  • Deciding not to have a default behaviour for a while - I think that giving it half a year and seeing how people use it will give us a lot of information, that said the window for introducing default behaviour is closing since it will start breaking peoples' code (assuming the behavior that will be decided on can break).

I think the most realistic option is to give this another few months and to document that default behavior will be introduced in the future. What do you think?

@meandmycode
Copy link

@meandmycode meandmycode commented Mar 8, 2015

My 2c here are that it may already be too late to add abortive behavior in, not only from io.js usage but how developers have been taught (or lack or teaching) from existing platforms, and the fact promises first landed in an environment that does not crash on unhandled exceptions has tainted the expectation (both of developers and its implementors).

The reality is that the concept of a maybe unhandled? rejection is bad, it exists to support bad/lazy programming but is also completely impossible to abstractly handle.. what am I going to do in this event callback realistically? who knows what this promise is, it may have come from 20 layers deep of dependent packages, developers will just end up having ON UNHANDLED -> IF DEBUG -> LOG

I will say that I would expect outreach to occur to stop third party libraries filling up event logs with pointless rejections, in which case you may as well have made the behavior correct anyway.

@MicahZoltu
Copy link

@MicahZoltu MicahZoltu commented May 26, 2015

export class MyData {
    constructor() {
        // prefetch to provide a better user experience
        this.resultPromise = http.get('http://www.google.com');
    }
}

export class ButtonClickHandler {
    onClick(myData) {
        // display spinner in case the promise is not yet fulfilled
        showSpinner();
        myData.resultPromise.then(result => {
            // display data to user
            showResult(result);
        }, error => {
            // display error to user
            showError(error);
        });
    }
}

In the above example, assume that MyData is constructed during application startup and the web request is kicked off right away, possibly before there is a reasonable UI to render errors to the user. At some point in the future, the user clicks some button and onClick is called. At that point in time, the promise is checked for its results.

I am of the opinion that this is a perfectly reasonable use case and generally a good practice. The promise is just an object that stores a future result or failure.

Many have related errors in promises to exceptions and I believe this is where the problem stems from. A promise is more akin to an if block than an exception. You are basically saying, "once this promise is fulfilled, run one of two code paths. You are not saying, "once this promise is fulfilled, run this code path or throw an exception." If you want the exception behavior then promises are not the right answer. You want some other construct that, while similar, does not keep rejected promises around.

@benjamingr benjamingr closed this Jan 24, 2016
@noinkling
Copy link

@noinkling noinkling commented Feb 4, 2016

@Zoltu

In this scenario, they simply use async/await and likely never have to work directly with a promise. If they forget a catch block, they'll get an exception in the console.

Correct me if I'm wrong or if I'm speaking out of place, but that's incorrect isn't it? Use of await requires an enclosing async function (I noticed that this was missing from your examples), so if you forget to use try/catch it just becomes the rejection value for the promise that that function returns instead, and you're back to where you started - you have to catch it somewhere or else it will be swallowed, therefore async/await has the exact same issue.

I only bring this up because, as a newcomer to Node, I ran into this myself recently while using async/await through Babel. If I'm any indication of what's to come, there will be people staring at their log output for half an hour wondering why their incoming server request is failing silently and timing out in the browser. In fact I did actually have a try/catch block in my function, but the error was occurring in a (decidedly synchronous) JSON.stringify call that I had ignorantly left outside it (lesson learned). If the unhandled rejection had been logged by default (much like it is in Chrome) I would have presumably seen the word "unhandled" along with the error and instantly known what I did wrong. As it stands I will be adding process.on('unhandledRejection', err => { console.error('Unhandled promise rejection ', err.stack); }); or similar to every Node application I build because of how informative it will be if I or anyone else using my code messes up again.

@MicahZoltu
Copy link

@MicahZoltu MicahZoltu commented Feb 7, 2016

@noinkling Hmm, in C# you aren't allowed to use await inside of a function that isn't marked as async. I didn't realize that ES allowed you to have a non-async function with await used inside of it. I never really thought about it before, but I wonder if this sort of problem is why C# forces you to mark your methods with await as async?

@noinkling
Copy link

@noinkling noinkling commented Feb 7, 2016

@Zoltu You misunderstand me, I'm saying that ES does currently require an enclosing async function in order to use await (though as I understand it, top-level await is being considered). You left it out in the examples you gave. Therefore, since any await requires an enclosing async function (which returns a promise), with the current Node behavior errors will never be logged by default, they will be swallowed just like any other promise unless explicitly handled, even if they are 'transformed' temporarily to exceptions within the function.

In other words, async/await doesn't solve anything with respect to the logging problem, which makes sense, since it's based on promises under-the-hood.

@MicahZoltu
Copy link

@MicahZoltu MicahZoltu commented Feb 8, 2016

Ah, you are right, I misunderstood you and I think you are correct, that async/await only helps if you are using it everywhere. If you are using await to interact with promises exclusively then you won't have any trouble and there shouldn't be any need for unhandled rejection handlers. If you are sometimes interacting with the promise directly (e.g., .then(...)) then you have to be more careful.

In my experience with C#, very few people interact with Tasks (promise equivalent) directly. They all interact with them via the await keyword. The only people who interact with Tasks directly are people who need more advanced control, which is the same set of people who would benefit from no unhandled rejection handler.

@noinkling
Copy link

@noinkling noinkling commented Feb 8, 2016

If you are using await to interact with promises exclusively then you won't have any trouble and there shouldn't be any need for unhandled rejection handlers. If you are sometimes interacting with the promise directly (e.g., .then(...)) then you have to be more careful.

There's no difference though (other than syntax) - either you use .catch with promises or try/catch with await, otherwise the error is silent. You have to handle it explicitly either way or nothing will be logged. To reiterate: async/await changes nothing in terms of logging behavior compared to promises, and therefore doesn't solve the issue of silent errors. In C# it might be different, I don't know.

@MicahZoltu
Copy link

@MicahZoltu MicahZoltu commented Feb 8, 2016

Perhaps I am misunderstanding something but as I understand it if you ALWAYS interact with promises via await then the only way you'll miss an exception is if you never looked at the result of a promise.

let fooPromise = getPromise(); // no throw here, we haven't tried to interact with the result yet
let barPromise = getPromise(); // will never throw, but since you never awaited the result it seems you don't really care
let foo = await fooPromise; // exception thrown here
actOnFoo(foo); // we'll either get here or we'll see an exception bubble up the stack
let fooPromise = getPromise();
let barPromise = getPromise();
fooPromise.then(result => {
    let foo = result;
    actOnFoo(foo); // we may never get here *AND* never see an exception, which is one reason why `await` is better
});

This practice depends on using async/await all the way up the call stack. Perhaps the issue you are referring to is the fact that at the very top (as you mentioned) you have to call your top level function. I agree, that Node should allow using await from top-level functions. In the meantime, I would recommend something like this:

async main() {
    // TODO: write application in here, use `await` everywhere interacting with promises
}

main().catch(error => console.log(error));

That being said, we are now getting into style questions and this style depends on not executing code in the global space (which seems to be very common in ES). C# has the same sort of problem, and you can see the same sort of answer here: http://stackoverflow.com/a/24601591/879046. Howover, since C# only has a single entry point which is a function, it isn't possible to accidentally execute code outside of the wrapped execution context so it is much harder to screw up than in Node.

@noinkling
Copy link

@noinkling noinkling commented Feb 8, 2016

Let me make a fairer comparison:

async function doAsyncStuff() {
  await promiseThatRejects();
}
doAsyncStuff().catch(error => console.log(error));

vs

function doAsyncStuff() {
  return promiseThatRejects();
}
doAsyncStuff().catch(error => console.log(error));

Anywhere that await can be used to propagate an error, returning the promise can be used to the same effect (which is typically how you work with promises in order to maintain a flat structure). Of course, the wrapper function in the 2nd example is unnecessary in this case, but it's needed to make a fair comparison and in real code would depend on context (due to interacting with other APIs or whatever). This might be more realistic:

async function doAsyncStuff() {
  try {
    await getPromise();
    // ...
  } catch (error) {
    console.log(error);
  }
}
doAsyncStuff();

vs

getPromise()
  .then(...)
  .catch(error => console.log(error));

But that's irrelevant to the issue at hand.

One of the main reasons for promises and async/await existing in the first place is to avoid a deeply-nested call stack, so error propagation up a stack shouldn't be much of a concern in the first place... but if for some reason it is, then async/await offers nothing that standard promises can't provide in this regard, and the fact remains that neither paradigm will do any logging without the error being explicitly caught and logged somewhere (yes, top-level counts).

If and when top-level await makes it into the language, then I think you might possibly have a point, depending on how errors at that level are handled. That's a big "if" and a big "when" though.

If you still disagree, feel free to PM me, I didn't mean to hijack the thread with this discussion.

@vkarpov15
Copy link

@vkarpov15 vkarpov15 commented Oct 19, 2016

I'm not gonna mince words, the "PromiseRejectionHandledWarning" default is crap DX. Much of the point of promises is that you can handle promise rejections asynchronously, now a bunch of perfectly valid promise patterns print spammy warnings unless you tweak the default.

before(function() {
  sinon.stub(obj.asyncFunction).returns(Promise.reject(err));
});

it('my test', function (done) {
  obj.asyncFunction.catch(error => {
    assert.ok(error);
    done();
  });
});
let lastPromise;

stream.on('data', () => {
  if (lastPromise) {
    lastPromise = lastPromise.then(() => doSomethingAsync(), () => doSomethingAsync());
  } else {
    lastPromise = doSomethingAsync();
  }
});

Etc. This warning is tangentially useful for debugging, but you need to remember to shut it off in prod and if you're doing anything even remotely non-trivial with promises.

@Fishrock123
Copy link
Member

@Fishrock123 Fishrock123 commented Oct 19, 2016

but you need to remember to shut it off in prod and if you're doing anything even remotely non-trivial with promises.

This would be correct, but being the default makes it usable by people who may not have as good of a hand on their potential problems.

@vkarpov15
Copy link

@vkarpov15 vkarpov15 commented Oct 19, 2016

Not necessarily, just makes perfectly valid patterns look scarier than they are and makes npm modules that do perfectly reasonable things print warnings upstream, making it so end users have to worry about module behavior. It isn't node's job to fix promise hell, that's what async/await or co/yield is for. Then, when people start blogging about async/await hell, you can come up with another half-baked "kid wheels mode" hack like domains for callbacks or logging warnings to the console for promises :)

@bminer
Copy link
Contributor

@bminer bminer commented Oct 19, 2016

I still think that the default (yet customizable) behavior for unhandled rejections is to crash the app, just like an uncaught exception.

If you want to handle a Promise rejection after it occurs, you can bind your own "unhandledRejection" handler to do just that. But, we cannot just ignore unhandled Promise rejections by default. Your custom "unhandledRejection" handler could do something like start a 30 second timer to see if the Promise is eventually handled. But, eventually, all Promise rejections should be handled... if not, it's probably a bug, perhaps even a bug that should intentionally crash the app.

Unhandled rejections are potentially just as dangerous as uncaught exceptions IMHO. The app could be in an undefined state. Even SyntaxErrors can result in unhandled rejections, for example.

@vkarpov15
Copy link

@vkarpov15 vkarpov15 commented Oct 19, 2016

So should every node module have its own special snowflake handler for on('unhandledRejection')? What if some module wants the behavior to be "crash the app" and another module wants it to be "ignore it"? Global behavior is global, no way for child libs to change it without risk of conflict. The point of this sort of feature is for the end user app to decide how it wants to handle unhandled rejections, not for node to decide what promise patterns should node modules be allowed to use, which is what it does now.

@bminer
Copy link
Contributor

@bminer bminer commented Oct 20, 2016

@vkarpov15 - To answer your question: Yes. IMHO, late binding a rejection handler is poor practice -- libs should avoid this pattern. If they really want to do it, they can have their own "unhandledRejection" handler.

Maybe Promises should have a flag to indicate that late binding is desired at the time of construction? Also, separate discussion but maybe Promises should have a .cancel() method to abort the async operation?

@vkarpov15
Copy link

@vkarpov15 vkarpov15 commented Oct 20, 2016

It's far from bad practice, it's necessary practice for more advanced use cases, which is what modules should be providing wrappers around anyway. Correct me if I'm wrong, but the 'unhandledRejection' handler is global to the process as a whole, which means a module that wants to crash on unhandled rejections will screw over every other module. TBH I understand your point, if you'd asked me in early 2015 I would've made a similar argument, "bad practice don't do it". But getting more comfortable with promises and spending time in observables land has made me realize that restricting promises to "let me just chain a bunch of HTTP / database calls together" is really a narrow view of what promises can do, which is what this default limits you to.

@benjamingr
Copy link
Member Author

@benjamingr benjamingr commented Oct 20, 2016

This discussion has been had several times and the consensus is to warn on it now and throw on GC when we have the hooks to do so.

It is easy to attach an empty catch handler which will suppress the warning.

There are at least 5 threads like this one - I recommend you look at the NodeJS/promises one if you want more up to date arguments.

@bminer
Copy link
Contributor

@bminer bminer commented Dec 1, 2016

Referencing a relevant PR here: #8217
Process warnings will occur starting in Node 7

@rsp
Copy link
Contributor

@rsp rsp commented Dec 2, 2016

I wrote the caught module to simplify working with use cases described by @MicahZoltu and @vkarpov15 without globally changing the behavior of everything by listening to the events.

It was originally written as an example for this answer on Stack Overflow: Should I refrain from handling Promise rejection asynchronously? but maybe it could be useful to someone who reads this discussion.

openui5bot pushed a commit to SAP/openui5 that referenced this issue Feb 7, 2018
To support a mixture of sync and async module loading, the ui5loader
creates a Promise for any requested resource to track its loading state,
even when the first requestor uses a synchronous API.

As long as no asynchronous API asks for the same resource, this promise
is never used. Modern browsers report a rejection of such a promise as
'Uncaught (in promise)' error and report it on the console.

One solution would be to create the Promise only on demand, but then
error tracking would be more complicated. As an alternative, this change
adds a dummy catch handler to the promise. This has no impact on error
reporting via APIs (errback - covered by tests).

For some background, see the discussion about rejected promises ( 
nodejs/node#830 ) and the current answer of
the HTML5 spec to the topic (
https://html.spec.whatwg.org/multipage/webappapis.html#unhandled-promise-rejections
)

Change-Id: I99e5c1384a4e5caf7ccdf21db1dfadbdc75884f3
openui5bot pushed a commit to SAP/openui5 that referenced this issue Mar 26, 2018
To support a mixture of sync and async module loading, the ui5loader
creates a Promise for any requested resource to track its loading state,
even when the first requestor uses a synchronous API.

As long as no asynchronous API asks for the same resource, this promise
is never used. Modern browsers report a rejection of such a promise as
'Uncaught (in promise)' error and report it on the console.

One solution would be to create the Promise only on demand, but then
error tracking would be more complicated. As an alternative, this change
adds a dummy catch handler to the promise. This has no impact on error
reporting via APIs (errback - covered by tests).

For some background, see the discussion about rejected promises ( 
nodejs/node#830 ) and the current answer of
the HTML5 spec to the topic (
https://html.spec.whatwg.org/multipage/webappapis.html#unhandled-promise-rejections
)

Change-Id: I99e5c1384a4e5caf7ccdf21db1dfadbdc75884f3
CR-Id: 002075125900000687202018
(cherry picked from commit 47ac957)
BCP: 1880209531
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
You can’t perform that action at this time.