question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add `Promise` API (Bonus: finally support)

See original GitHub issue

An opt-in Promise API is the best avenue for adding finally support.

Likely, the callback API will be deprecated at a point that makes sense and avoids as much inconvenience as possible for the community

Issue Analytics

  • State:open
  • Created 8 years ago
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
CrabDudecommented, Feb 6, 2017

This would be implemented in lib/trycatch.js.

Off the top of my head, the way unhandledRejection works presently is that for every promise exception, it adds an asynchronous check for whether the rejection was handled synchronously. At that point, instead of process.emit('unhandledRejection', error), you would need to process.domain.emit('error', error), which should automatically get routed to the relevant catch handler.

It’s not immediately obvious how to accomplish the above without mucking with / coupling the implementation to node.js internals (e.g., promise.js). However, we can take advantage of a few things and create poor-man’s version of this for the time being, that should be sufficient:

  1. EventEmitter.prototype.emit is synchronous and serial.
  2. trycatch already wraps/shims & catches errors thrown from EventEmitter handlers.
  3. EventEmitter.prototype.emit ignores setting the active domain for process event handlers.
  4. trycatch is mean to be the first require in your process to properly shim core APIs.

Given the above, merely adding the following should/might be sufficient:

// process.domain.emit cannot be passed directly b/c it changes dynamically
process.on('unhandledRejection', function(e) {
    // This will be caught be the active domain...
    // ... And avoids emitting on other unhandledRejection handlers
    // Active domain error handler is the relevant trycatch catch function
    if (process.domain && !process.domain._disposed) throw e
})

// Run the above just before the hookit call that wrap core...
// ... to avoid wrapping the handler (and mucking with the active domain)
// ... Though given the special EventEmitter logic for process, this probably doesn't matter

// Pass callback wrapping function to hookit
hookit(wrap)

You could verify this by adding a test that does the following:

var err = new Error('This should get passed to catchFn')

trycatch(function catchFn() {
    setImmediate(function() {
        // Create a rejected promise that has no reject handler
        Promise.reject(err)
    })
}, function catchFn(e) {
    assert.equals(err, e)
})

The existing test suite (npm test) is fairly comprehensive, but there would be several other tests needed to fully cover this new functionality. Off the top of my head:

  1. catchFn should be async
  2. Long stack traces are as expected
  3. process.on('unhandledRejection', ...) & process.on('uncaughtException', ...) do not fire.
  4. Ensure pre-existing domain (set prior to trycatch(...) does not interfere.
  5. Ensure numerous peer & nested trycatch calls work as expected & do not interfere.

Finally, this will only work for promise implementations that properly emit process.on('unhandledRejection', ...), and so will be incompatible with any homegrown solutions that do not do so. That said, it seems to be getting standardized / convention-ized, so it will likely be sufficient, and won’t break anything.

Let me know if that works. Thanks for taking the time to work on this. Happy to help as best I can given my limited availability.

1reaction
CrabDudecommented, Feb 6, 2017

It’s actually totally possible, but a little more invasive than try catch already is. Effectively, you would need to track all Errors in Error.prepareStackTrace, and then filter for unhandledRejection errors.

You could implement this fairly easily by slightly augmenting an existing userspace implementation of onUnhandledRejection, but instead of emitting the error on the process.onUnhandledRejection event, you would just pass it to the current context’s active catch call back / handler (when it exists) instead.

This wouldn’t really add any additional functionality that is not already provided via the process.onUnhandledRejection event and long stack traces, except the ability to catch in context. It would be like a request (500) level unhandledRejection.

That is something that would be nice to have.

Read more comments on GitHub >

github_iconTop Results From Across the Web

JavaScript Promises: an introduction - web.dev
Promises simplify deferred and asynchronous computations. A promise represents an operation that hasn't completed yet.
Read more >
Wait until all promises complete even if some rejected
The Promise.all will swallow any rejected promise and store the error in a variable, so it will return when all of the promises...
Read more >
Asynchronous Dancer2 PT. 2 - Promises and a Bonus!
Here is a bit of a trick. A promise is meant for only one value, which normally means only one asynchronous action. We...
Read more >
Promises and design patterns in AngularJS - Xebia
The CommonJS standards committee has released a spec that defines this API called Promises. The concept behind promises is pretty simple, ...
Read more >
Understanding Axios POST requests - LogRocket Blog
First, Axios allows us to work with only one promise( .then() ) and with JSON data by default unlike in the Fetch API...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found