metarhia / metasync

Asynchronous Programming Library for JavaScript & Node.js
https://metarhia.com
MIT License
206 stars 35 forks source link

Implement `runIf()` function #410

Closed belochub closed 5 years ago

belochub commented 5 years ago

We need a function that will allow to call an asynchronous function optionally, example common use case:

const { asyncFn, syncFn } = require('./localdep');

function f(a, b, callback) {
  const cb = err => {
    if (err) {
      callback(err);
      return;
    }
    const result = syncFn(b);
    callback(null, result);
  };
  if (a) {
    asyncFn(b, cb);
  } else {
    cb(null);
  }
}

In this example, the fact that the common callback (cb) is declared before it is used and, in my opinion, that disrupts the flow and hurts readability.

The solution to the problem may be introducing the function that will optionally call the asynchronous function, and will call the callback immediately if it isn't called. Updated example:

const { runIf } = require('metasync');
const { asyncFn, syncFn } = require('./localdep');

function f(a, b, callback) {
  runIf(a, asyncFn, err => {
    if (err) {
      callback(err);
      return;
    }
    const result = syncFn(b);
    callback(null, result);
  });
}

It should also possibly allow to pass some default value to the callback that would otherwise be retrieved from the asynchronous function, for example:

const { runIf } = require('metasync');
const { asyncFn, syncFn } = require('./localdep');

function f(a, b, callback) {
  runIf(a, 'some default value', asyncFn, (err, val) => {
    if (err) {
      callback(err);
      return;
    }
    // here `val` is 'some default value' if the `asyncFn()` isn't called
    const result = syncFn(b, val);
    callback(null, result);
  });
}

Possible implementation may look something like:

const runIf = (condition, defaultVal, asyncFn, ...args) => {
  if (typeof defaultVal === 'function') {
    args.unshift(asyncFn)
    asyncFn = defaultVal;
    defaultVal = undefined;
  }
  if (condition) {
    asyncFn(...args);
  } else {
    const callback = args[args.length - 1];
    callback(null, defaultVal);
  }
}
o-rumiantsev commented 5 years ago

Maybe, it would be nice to handle AsyncFunction as asyncFn too?