golike-defer

go's defer statement in JavaScript

Usage no npm install needed!

<script type="module">
  import golikeDefer from 'https://cdn.skypack.dev/golike-defer';
</script>

README

golike-defer

Node compatibility PackagePhobia

Package Version Build Status Latest Commit

go's defer statement in JavaScript

defer() is a function decorator which injects a $defer() function as a first parameter.

This injected function can be used to register deferreds, functions which will be executed at the end of the decorated function execution, no matter how it ended (via a return or a throw).

Note: the deferreds are executed in the reverse order of their declarations.

Install

Installation of the npm package:

> npm install --save golike-defer

Usage

import { defer } from 'golike-defer'

const fn = defer(
  // Works both with sync and async functions
  async function($defer, ...args) {
    $defer(() => {
      console.log("always called at the end of the function");
    });

    $defer.onFailure(() => {
      console.log("called at the end of the function only on failure");
    });

    $defer.onSuccess(() => {
      console.log("called at the end of the function only on success");
    });
  }
);

Context and arguments can be passed to the deferred function:

  • $defer(cb): called without context nor arguments
  • $defer(cb, arg1, arg2): called with arguments arg1 and arg2
  • $defer.call(thisArg, cb): called with context thisArg
  • $defer.call(thisArg, 'method'): thisArg.method called with context thisArg

Example

import { defer } from 'golike-defer'
import fs from 'fs'

const readFileSync = defer(($defer, path) => {
  const fd = fs.openSync(path, 'r')

  // The file will be automatically closed at the end of the function,
  // whether it succeed or failed.
  $defer(fs.closeSync, fd)

  const { size } = fs.statSync(path)

  const buffer = Buffer.allocUnsafe(size)
  fs.readSync(fd, buffer, 0, buffer.length)

  return buffer
})

// Helper to promisify a function call.
const fromCallback = fn => new Promise((resolve, reject) => {
  fn((error, result) => error ? reject(error) : resolve(result))
})

const readFile = defer(async ($defer, path) => {
  const fd = await fromCallback(cb => fs.open(path, 'r', cb))

  // The file will be automatically closed at the end of the function,
  // whether it succeed or failed.
  $defer(() => fromCallback(cb => fs.close(fd, cb)))

  const { size } = await fromCallback(cb => fs.stat(path, cb))

  const buffer = Buffer.allocUnsafe((size)
  await fromCallback(cb => fs.read(fd, buffer, 0, buffer.length, cb))

  return buffer
})

On error

Exceptions (or rejected promises) thrown in deferred are caught and printed on the console.

This can be customized with the onError() method:

const myDefer = defer.onError(error => {
  log(error);
});

const fn = myDefer(($defer, arg1, arg2) => {
  // ...
});

Development

# Install dependencies
> npm

# Run the tests
> npm test

# Continuously compile
> npm run dev

# Continuously run the tests
> npm run dev-test

# Build for production (automatically called by npm install)
> npm run build

Contributions

Contributions are very welcomed, either on the documentation or on the code.

You may:

  • report any issue you've encountered;
  • fork and create a pull request.

License

ISC © Julien Fontanet