GithubHelp home page GithubHelp logo

sindresorhus / loud-rejection Goto Github PK

View Code? Open in Web Editor NEW
281.0 281.0 24.0 42 KB

Make unhandled promise rejections fail loudly instead of the default silent fail

License: MIT License

JavaScript 97.27% TypeScript 2.73%

loud-rejection's Introduction

loud-rejection

Make unhandled promise rejections fail loudly instead of the default silent fail

By default, promises fail silently if you don't attach a .catch() handler to them.

This tool keeps track of unhandled rejections globally. If any remain unhandled at the end of your process, it logs them to STDERR and exits with code 1.

Use this in top-level things like tests, CLI tools, apps, etc, but not in reusable modules.
Not needed in the browser as unhandled rejections are shown in the console.

With Node.js 15, this package is moot as the default behavior then is to throw on unhandled rejections.

Install

$ npm install loud-rejection

Usage

const loudRejection = require('loud-rejection');
const promiseFunction = require('promise-fn');

// Install the `unhandledRejection` listeners
loudRejection();

promiseFunction();

Without this module it's more verbose and you might even miss some that will fail silently:

const promiseFunction = require('promise-fn');

function error(error) {
	console.error(error.stack);
	process.exit(1);
}

promiseFunction().catch(error);

Register script

Alternatively to the above, you may simply require loud-rejection/register and the unhandledRejection listener will be automagically installed for you.

This is handy for ES2015 imports:

import 'loud-rejection/register';

API

loudRejection([log])

log

Type: Function
Default: console.error

Custom logging function to print the rejected promise. Receives the error stack.

Related

  • hard-rejection - Make unhandled promise rejections fail hard right away instead of the default silent fail
  • More…

Get professional support for this package with a Tidelift subscription
Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies.

loud-rejection's People

Contributors

bendingbender avatar callumlocke avatar coreyfarrell avatar dylanvann avatar jamestalmage avatar linusu avatar ntwb avatar richienb avatar sindresorhus avatar timdp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

loud-rejection's Issues

I was going to clean it up, I promise!

I don't know if there is much we can do about this, but it would be very cool if this didn't throw an error.

var loudRejection = require('loud-rejection')

loudRejection()

var myp

setTimeout(function () {
  myp = new Promise(function (resolve, reject) {
    setTimeout(reject, 100, new Error('Silence me'))
  })
}, 100)

setTimeout(function () {
  myp.catch(function (err) {
    console.log('Catched!')
  })
}, 300)

I think that it has to go into the Promise implementation thought, and I guess that that ship has sailed.

My idea was to do this when the promise is thrown away by the garbage collector, if it hasn't been handled by then it won't ever be. But maybe this has problems as well?

Should I use this in tests?

README.md:

Should NOT be used in reusable modules. Only in top-level apps / CLI tools.

That makes sense. But what about using it in tests for reusable modules?

For example, mocha now lets me return a promise. But let's say I forget to actually type return, so I just have a loose promise:

it('does something', function () {
  foo().then(function (result) {
     assert(result.isGood);
  });
});

..the test passes immediately, then some time later my promise silently fails.

Would you recommend calling loud-rejection at the top of any test script?

Use of the "unhandledRejection" event.

Why not just add the event unhandledRejection? No lib/dep required. While newer NodeJS versions will handle it automatically.

process.on('unhandledRejection', ex => {
  console.error(ex);
  // Optional throw an error / terminate the process.
  process.exit(1);
});

DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

https://nodejs.org/api/process.html#process_event_unhandledrejection

Add a 'register' script

It would be nice if there was a register.js script in the root so we could do this:

import 'loud-rejection/register';

Option to exit without modifying the exit code.

Right now loud-rejection forces a non-zero exit code.

When used in test runners that fork processes (i.e. AVA), that may not be the desired outcome.

Mocha (for example), does not fail tests due to unhandledRejections, but it does print. them.

Breaking change between minor versions

After a long debugging session I ended up in the loud-rejection source and found that its behaviour has completely changed since v1.0.0:

  • v1.0.0: if a promise goes unhandled, kill the process.
  • v1.1.0: if a promise goes unhandled, keep track of it in a secret array which is only printed out if and when the process exits for some other reason.

The first problem is, this should have been a major version bump. It's a backwards-incompatible change that has broken a lot of my server apps, which expected the process to exit if a promise goes unhandled (just as it does when an exception goes uncaught).

Second, it means loud-rejection is no longer appropriate for a whole set of use cases, such as server apps, or anything else that is supposed to run indefinitely. Contrived example (which behaves completely differently after the minor bump to v1.1.0):

import 'loud-rejection/register';
import express from 'express';

const app = express();

app.get('/', async function (req, res) {
  console.log('something');
  if (x) throw new Error('foo');

  res.send('hi');
});

In the above code, here's what happens when a browser requests http://localhost/ when x is truthy: the server app logs "something" and then the request just hangs forever – the 'foo' error is never logged, despite loud-rejection having been registered. You can refresh the browser several times and you just see "something" logged again and again. Later, when you manually kill the process with ctrl+C, only then do you see all the 'foo' errors printed out.

Finally, in my opinion this change shouldn't have been made at all, even with a major bump. In my experience, the only times I've ever wanted to swoop in and attach an error handler to an already-rejected promise are when I'm doing some horrible hack that I shouldn't be doing. It's an antipattern. If you think you want to leave a promise unhandled until you maybe inspect its outcome later, then what you really want is to catch it and store the success/failure information in a variable for later inspection. Or you could 'settle' the promise's outcome into something inspectable (using e.g. Bluebird's .reflect() or just p.then(x, y).then(settled => {...})). A rejection is supposed to be the async analog to an exception, it shouldn't go uncaught unless you want it to be fatal.

error logs only at exit

env

$ node -p 'process.versions'
{ http_parser: '2.7.0',
  node: '7.6.0',
  v8: '5.5.372.40',
  uv: '1.11.0',
  zlib: '1.2.11',
  ares: '1.10.1-DEV',
  modules: '51',
  openssl: '1.0.2k',
  icu: '58.2',
  unicode: '9.0',
  cldr: '30.0.3',
  tz: '2016j' }

$ npm -v
4.1.2

example code

'use strict'

require('loud-rejection/register')

async function main(){
  throw new Error('boom')
}

main()

setTimeout(function() {
  // none
}, 20000000);

behaviors

$ node index.js
^CError: boom
    at main (/Users/magicdawn/projects/001_learn/node/index.js:6:9)
    at Object.<anonymous> (/Users/magicdawn/projects/001_learn/node/index.js:9:1)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.runMain (module.js:605:10)
    at run (bootstrap_node.js:422:7)
    at startup (bootstrap_node.js:143:9)

the boom stack prints after I press Ctrl+C kill the process.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.