0.0.1 • Published 7 years ago

promise-maker v0.0.1

Weekly downloads
1
License
ISC
Repository
github
Last release
7 years ago

Promise-Maker

A simple, straight-forward approach to converting callback-based async functions into Promise-based equivalents.

Install and use with: npm install --save promise-maker

Example 1, making a promise-based version of a callback-based method:
var pMaker = require('promise-maker')
var fs = require('fs')

//create promise-based version of desired method
var pRead = pMaker.create(fs.readFile)

//how you would use the standard callback version
fs.readFile('/path/to/resource.json', 'utf-8', function(err, data){
  if(err){
     console.log(err)
  }else{
    data = JSON.parse(data)
    console.log(data)
})

//compare with the promise-maker produced version
pRead('/path/to/resource.json', 'utf-8')
  .then(JSON.parse)
  .then(console.log)
  .catch(console.log)
Example 2, running a callback-based method in Promise-based form on a one-time basis:
var pMaker = require('promise-maker')
var fs = require('fs')

pMaker.complete(fs.readFile, '/path/to/resource.json', 'utf-8')
  .then(JSON.parse)
  .then(console.log)
  .catch(console.log)
Example 3, turning embedded callback-based methods into chainable Promises:
var pMaker = require('promise-maker')
var fs = require('fs')

/*Goal: read a file, parse its content,
make an update to its content, and save
the updated version to the original filepath*/

//with callbacks
fs.readFile('/path/to/resource.json', 'utf-8', function(err, data){
  if(err){
    console.log(err)
  }else{
    data = methodToUpdateFileContent(JSON.parse(data))
    fs.writeFile('/path/to/resource.json', data, function(err){
      if(err){
        console.log(err)
      }else{
        console.log('File update completed.')
      }
    })
})

//creating and using Promise-based methods
var pRead = pMaker(fs.readFile)
var pWrite = pMaker(fs.writeFile)

pRead('/path/to/resource.json', 'utf-8')
  .then(JSON.parse)
  .then(methodToUpdateFileContent)
  .then(data => pWrite(file, data))
  .then(()=> console.log('File update completed.'))
  .catch(console.log)

//run as promise-based methods on one-time basis
pMaker.complete(fs.readFile, '/path/to/resource.json', 'utf-8')
  .then(JSON.parse)
  .then(methodToUpdateFileContent)
  .then(data => pMaker.complete(fs.writeFile, '/path/to/resource.json', data))
  .then(()=> console.log('File update completed.'))
  .catch(console.log)

How Will My Promise Know Which Value to Pass to resolve()?

By default, promise-maker follows the Node.js standard callback argument pattern for determining which value a Promise should pass to resolve() (or reject()). The Node.js pattern involves an error hook being passed as the first argument to the callback, followed by the target value of interest as the second argument--for example, cb(err, data). Any method which follows this standard callback pattern should be fully compatible with promise-maker right away. For async methods that deviate from this Node.js pattern in a substantial manner though, conversion is still possible by overriding the default rules for selecting a value for Promise resolution (see 'Overriding Standard Value Selection for resolve() below).

The default approach to value selection is as follows:

  • If an error hook is traditionally passed to the async method's callback for handling, and an error has occurred, the Promise will reject() with the value of the error object that would normally have been passed to the callback. If an error has not occurred, promise-maker will turn its attention to determining if another value should be passed to resolve().
  • If the async callback within the method would usually be passed 1 argument, this will become the resolve() value for the Promise (this is still the case, even for async methods that only pass an error hook to the callback; if an error has not occurred, the Promise will simply resolve with the null value held in place of the absent error; this in turn will trigger the next .then() statement following your Promise).
  • If the async callback within the method is usually passed 2 arguments, the first argument is assumed to be the standard error hook used by the typical Node.js callback pattern, and the second argument will become the resolve() value.
  • If the async callback within the method would usually be passed 3+ arguments, it will be assumed that the callback pattern does not follow the Node.js standard and the arguments that would be passed to the callback will instead all be resolved together as an array, to give the user access to all of the potential values.

Overriding Standard Value Selection For resolve()

If your async method follows a callback argument pattern that conflicts with the default rules outlined above, you can override these rules using a second optional argument with the create() method, called the resolves parameter. This parameter cannot be set for the complete() method, therefore, if you wish to convert a callback-based method to a Promise-based version, and that callback-based method is not compatible with the default resolve() values indicated above, you must use create() to produce a new Promise-based method, instead of attempting to use complete() to run the method as a Promise on a one-time only basis.

When setting the resolves parameter, the following options are made available:

  • index number: If resolves is set to a number, this number will be applied to an array of the potential callback arguments, with the number serving as an index identifier for the value you would like to see passed to resolve() (i.e. a resolves value of 0 selects the first argument from the argument array to be passed to resolve(), a value of 1 selects the second argument array value, and so on). Example 1: If your target method would normally pass three values to the callback, but you are only interested in the third value (instead of the default, which would resolve() all three as an array), you could target this value with the following: pMake.create(lotsOfCallbackVals, 2). Example 2: Say you have an async method that reverses the standard Node.js argument pattern, passing the desired data as the first argument, with an error hook as the second argument (cb(data, err), as opposed to cb(err, data)), you can instruct your Promise to resolve with the first argument (index 0 in the arguments array), instead of the usual second argument (index 1 of the array), by passing 0 as the resolves parameter: pMake.create(dataComesFirstMethod, 0).

  • 'all': If you want your promise to resolve() with all of the arguments that would usually be passed to the callback, regardless of how many argument values there are, this can be accomplished by setting the resolves parameter to 'all'. This will lead to all potential callback arguments being resolved as a singular array. Example: If your async method's callback is normally passed two arguments, but you want both of them passed to resolve() (instead of the default setting, which would only pass the second argument), this can be accomplished with: pMake.create(needBothValsMethod, 'all').

  • true: In some cases, you will only be interested in knowing when (and if) your method call has successfully completed. In such cases, you can use the boolean value of true as your resolves parameter. This has the effect of setting your new Promise-based method to pass true to resolve() upon method completion, while still allowing both for error hooks to be screened, as well as for efficient flow control of asynchronous execution. Example: If you are using a method that only passes an error hook to the usual callback, such as fs.writeFile, but would like the Promise-based version to resolve with true, instead of null, upon successful completion of file writing, this can be accomplished with: pMake.create(fs.writeFile, true).

API

create(func, [resolves])

  • func: The callback-based async method you wish to convert to a Promise-based method.
  • resolves(optional): Target value you would like your Promise to pass to resolve() (if different from default resolve() target value).

complete(func, ...args)

  • func: The callback-based async method you wish to have executed on a one-time basis as a Promise.
  • ...args: The arguments you would usually pass to the main async function, represented by func, when calling it.