hybridables/try-catch-core

View on GitHub
.verb.md

Summary

Maintainability
Test Coverage
<p align="center">
  <a href="https://github.com/hybridables">
    <img height="250" width="250" src="https://avatars1.githubusercontent.com/u/10666022?v=3&s=250">
  </a>
</p>

# {%= name %} {%= badge('npm') %} {%= badge('downloads') %} [![npm total downloads][downloads-img]][downloads-url]

> {%= description %}

[![codeclimate][codeclimate-img]][codeclimate-url] 
[![codestyle][standard-img]][standard-url] 
[![linux build][travis-img]][travis-url] 
[![windows build][appveyor-img]][appveyor-url] 
[![codecov][coverage-img]][coverage-url] 
[![dependency status][david-img]][david-url]

## Install
```
npm i {%= name %} --save
```

## Usage
> For more use-cases see the [tests](./test.js)

```js
const fs = require('fs')
const {%= varname %} = require('{%= name %}')

{%= varname %}((cb) => {
  fs.readFile('./package.json', 'utf8', cb)
}, (err, res) => {
  if (err) return console.error(err)

  let json = JSON.parse(res)
  console.log(json.name) // => '{%= name %}'
})
```

## Background
Why this exists? What is useful for? What's its core purpose and why not to use something other? Why not plain try/catch block? What is this?

### What is this?
Simply said, just try/catch block. But on steroids. Simple try/catch block with a callback to be called when some function completes - no matter that function is asynchronous or synchronous, no matter it throws.

### Why this exists?
> There are few reasons why this is built.

- **simplicity:** built on [try-catch-callback][], [once][] and [dezalgo][] - with few lines of code
- **flexibility:** allows to pass custom function context and custom arguments
- **guarantees:** completion is always handled and always in next tick
- **low-level:** allows to build more robust wrappers around it in higher level, such as [always-done][] to handle completion of **anything** - observables, promises, streams, synchronous and async/await functions.

### What is useful for?
It's always useful to have low-level libs as this one. Because you can build more higher level libs on top of this one. For example you can create one library to handle completion of generator functions. It would be simply one type check, converting that generator function to function that returns a promise, than handle that promise in the callback.

Brilliant example of higher level lib is [always-done][] which just pass given function to this lib, and handles the returned value inside callback with a few checks.

Another thing can be to be used as _"thunkify"_ lib, because if you does not give a callback it returns a function (thunk) that accepts a callback.

### Why not plain try/catch?
Guarantees. This package gives you guarantees that you will get correct result and/or error of execution of some function. And removes the boilerplate stuff. Also works with both synchronous and asynchronous functions. But the very main thing that it does is that it calls the given callback in the next tick of event loop and that callback always will be called only once.

**[back to top](#readme)**

## API
{%= apidocs('index.js') %}

**[back to top](#readme)**

## Supports
> Handle completion of synchronous functions (functions that retunrs something) and asynchronous (also known as callbacks), but not `async/await` or other functions that returns promises, streams and etc - for such thing use [always-done][].

### Successful completion of sync functions

```js
const {%= varname %} = require('{%= name %}')

{%= varname %}(() => {
  return 123
}, (err, res) => {
  console.log(err, res) // => null, 123
})
```

**[back to top](#readme)**

### Failing completion of synchronous

```js
const {%= varname %} = require('{%= name %}')

{%= varname %}(() => {
  foo // ReferenceError
  return 123
}, (err) => {
  console.log(err) // => ReferenceError: foo is not defined
})
```

**[back to top](#readme)**

### Completion of async functions (callbacks)

```js
const fs = require('fs')
const {%= varname %} = require('{%= name %}')

{%= varname %}((cb) => {
  // do some async stuff
  fs.readFile('./package.json', 'utf8', cb)
}, (e, res) => {
  console.log(res) // => contents of package.json
})
```

**[back to top](#readme)**

### Failing completion of callbacks

```js
const fs = require('fs')
const {%= varname %} = require('{%= name %}')

{%= varname %}((cb) => {
  fs.stat('foo-bar-baz', cb)
}, (err) => {
  console.log(err) // => ENOENT Error, file not found
})
```

**[back to top](#readme)**

### Passing custom context

```js
const {%= varname %} = require('{%= name %}')
const opts = {
  context: { foo: 'bar' }
}

{%= varname %}(function () {
  console.log(this.foo) // => 'bar'
}, opts, () => {
  console.log('done')
})
```

**[back to top](#readme)**

### Passing custom arguments
> It may be strange, but this allows you to pass more arguments to that first function and the last argument always will be "callback" until `fn` is async or sync but with `passCallback: true` option.

```js
const {%= varname %} = require('{%= name %}')
const options = {
  args: [1, 2]
}

{%= varname %}((a, b) => {
  console.log(arguments.length) // => 2
  console.log(a) // => 1
  console.log(b) // => 2

  return a + b + 3
}, options, (e, res) => {
  console.log(res) // => 9
})
```

**[back to top](#readme)**

### Returning a thunk
> Can be used as _thunkify_ lib without problems, just don't pass a done callback.

```js
const fs = require('fs')
const {%= varname %} = require('{%= name %}')
const readFileThunk = {%= varname %}((cb) => {
  fs.readFile('./package.json', cb)
})

readFileThunk((err, res) => {
  console.log(err, res) // => null, Buffer
})
```

**[back to top](#readme)**

{% if (verb.related && verb.related.list && verb.related.list.length) { %}
## Related
{%= related(verb.related.list, {words: 12}) %}
{% } %}

## Contributing
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/{%= repository %}/issues/new).  
Please read the [contributing guidelines](CONTRIBUTING.md) for advice on opening issues, pull requests, and coding standards.  
If you need some help and can spent some cash, feel free to [contact me at CodeMentor.io](https://www.codementor.io/tunnckocore?utm_source=github&utm_medium=button&utm_term=tunnckocore&utm_campaign=github) too.

**In short:** If you want to contribute to that project, please follow these things

1. Please DO NOT edit [README.md](README.md), [CHANGELOG.md](CHANGELOG.md) and [.verb.md](.verb.md) files. See ["Building docs"](#building-docs) section.
2. Ensure anything is okey by installing the dependencies and run the tests. See ["Running tests"](#running-tests) section.
3. Always use `npm run commit` to commit changes instead of `git commit`, because it is interactive and user-friendly. It uses [commitizen][] behind the scenes, which follows Conventional Changelog idealogy.
4. Do NOT bump the version in package.json. For that we use `npm run release`, which is [standard-version][] and follows Conventional Changelog idealogy.

Thanks a lot! :)

## Building docs
Documentation and that readme is generated using [verb-generate-readme][], which is a [verb][] generator, so you need to install both of them and then run `verb` command like that

```
$ npm install verbose/verb#dev verb-generate-readme --global && verb
```

_Please don't edit the README directly. Any changes to the readme must be made in [.verb.md](.verb.md)._

## Running tests
Clone repository and run the following in that cloned directory

```
$ npm install && npm test
```

## Author
{%= includeEither('authors', 'author') %}
+ [codementor/tunnckoCore](https://codementor.io/tunnckoCore)

## License
{%= copyright({ start: 2016, linkify: true, prefix: 'Copyright', symbol: '©' }) %} {%= license %}

***

{%= include('footer') %}  
_Project scaffolded using [charlike][] cli._

{%= reflinks(verb.reflinks) %}

[downloads-url]: https://www.npmjs.com/package/{%= name %}
[downloads-img]: https://img.shields.io/npm/dt/{%= name %}.svg

[codeclimate-url]: https://codeclimate.com/github/{%= repository %}
[codeclimate-img]: https://img.shields.io/codeclimate/github/{%= repository %}.svg

[travis-url]: https://travis-ci.org/{%= repository %}
[travis-img]: https://img.shields.io/travis/{%= repository %}/master.svg?label=linux

[appveyor-url]: https://ci.appveyor.com/project/tunnckoCore/{%= name %}
[appveyor-img]: https://img.shields.io/appveyor/ci/tunnckoCore/{%= name %}/master.svg?label=windows

[coverage-url]: https://codecov.io/gh/{%= repository %}
[coverage-img]: https://img.shields.io/codecov/c/github/{%= repository %}/master.svg

[david-url]: https://david-dm.org/{%= repository %}
[david-img]: https://img.shields.io/david/{%= repository %}.svg

[standard-url]: https://github.com/feross/standard
[standard-img]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg