1.1.0 • Published 4 years ago

async-unwrap v1.1.0

Weekly downloads
23
License
MIT
Repository
github
Last release
4 years ago

Async-await can help you write some amazing-looking and very readable code, but if you're anything like me, you probably hate burying it into try-catch blocks. With async-unwrap, you can go from this:

async () => {
  try {
    await someAsyncOperation()
  } catch (err) {
    doSomething(err)
  }
}

to this:

async () => {
  const [err, result] = await someAsyncOperation()[unwrap]
  if (err) return doSomething(err)
}

But how?

First, you need to say the magic word:

const unwrap = require('async-unwrap')
// or if the above is way too old for you:
import unwrap from 'async-unwrap'

This gives you a symbol that's attached to the prototype of every promise (or other thenable), which turns that promise into another one. The "unwrapped" promise will resolve to a tuple two-element array of [null, result] if the base promise is resolved and [err, null] if it's rejected. This allows you to handle your errors in a slightly different way, without breaking the block scope.

If you're using multiple async calls in a function, I'd recommend structuring your code in the following way:

async () => {
  const [firstError, firstResult] = await firstOperation()[unwrap]
  if (firstError) throw firstError // we'll handle it on a higher level

  const [secondError, secondResult] = await secondOperation(firstResult)[unwrap]
  if (secondError) throw sanitize(secondError) // sometimes you'll need some special treatment

  return secondResult
}

Exercise to the reader: try writing that without nested try-catch blocks or falling back to let.

Local offensive

Before you ask, yes, that does modify global variables, specifically Object.prototype, which is actually the variable you should have the most caution with modifying. async-unwrap uses a symbol to define a non-enumerable getter, minimizing the surface for errors (it's practically invisible in normal usage), but in some exotic cases you might still run into problems with that. If you'd like to not take that chance, there is a "function" variant of the library:

import unwrap from 'async-unwrap/func'

async () => {
  const [err, result] = await unwrap(someAsyncOperation())
  if (err) return doSomething(err)
}

Why is this not the default? Well, frankly because I think it's ugly, but to each their own. You can use the function variant if you'd like to, no hard feelings.

Compatibility

Everything, theoretically. The library binds to all objects and simply checks for a then() method, which is the JS spec's way of deciding if something is a promise. This should enable it to work seamlessly with custom promise implementations. If you still run into any compatibility issues, please submit a bug report.

Contributing

Pull requests are welcome. As always, be respectful towards each other and maybe run or create tests, as appropriate. It's on npm test, as usual.

async-unwrap is available under the MIT license.

1.1.0

4 years ago

1.0.2

5 years ago

1.0.1

6 years ago

1.0.0

6 years ago