14

In a promise library bluebird have function promisifyAll or other similar libraries that claim to convert async functions with callback patterns into promise based ie. resolve(), reject(), or done()..So how does it work?

For example:

function myAsync1 (data, url, callBack) {...}

and if i put it in

Promise.promisify(myAsycn1);

then will my function work like this..

myAsync1('{..}', 'http://..').then(function(){...});

This is have been bothering me. Is there a pattern that async non promise libs or function need to follow for Bluebird promisifyAll to convert them to promises based methods or there is some magic that converts them.

If not then what are the requirements and how does it work with existing libraries like mongodb etc.

Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
Muhammad Umer
  • 17,263
  • 19
  • 97
  • 168
  • Notice that your function is not "converted", functions are immutable. Instead, `Promise.promisify` does return a *new* function that will call the old with the callback. – Bergi Apr 13 '15 at 00:05
  • 2
    possible duplicate of [Trying to understand how promisification works with BlueBird](http://stackoverflow.com/q/26391419/1048572) – Bergi Apr 13 '15 at 00:06
  • @Bergi it may be a duplicate but its title worded so badly in terms of SEO that after searching for four hours i didn't come across it once remotely, in fact it's more on side of click bait. – Muhammad Umer Apr 13 '15 at 02:19
  • However, Billion thanks for sharing that link it confirms and clarifies many things!!! – Muhammad Umer Apr 13 '15 at 02:29

2 Answers2

23

Is there a pattern that async non promise libs or function need to follow for Bluebird promisifyAll to convert them to promises based methods

Yes, there is a pattern. The functions it converts must expect a callback as their last argument. Additionally, it must pass an error as the first argument to the callback (null if no error) and the return value as the second argument.

The BlueBird promisify function is very difficult to follow because of optimizations, so I'll show a simple way it could be written:

function promisify(fn) {
  return function() {
    var that = this; // save context
    var args = slice.call(arguments); // turn into real array
    return new Promise(function(resolve, reject) {
      var callback = function(err, ret) { // here we assume the arguments to
                                          // the callback follow node.js
                                          // conventions
        if(err != undefined) {
          reject(err);
        } else {
          resolve(ret);
        }
      };
      fn.apply(that, args.concat([callback])); // Now assume that the last argument will
                                              // be used as a callback
    });
  };
}

Now we could implement promisifyAll by looping over the functions in the target object and using promisify on each one.

Gab
  • 7,869
  • 4
  • 37
  • 68
Aaron Dufour
  • 17,288
  • 1
  • 47
  • 69
  • so if this the convention then does it mean asyncjs doesn't follow the convention? https://gist.github.com/techsin/18a6b6d36ed0205a443a In this you can see that functions work if only the callback is the first argument. Is this behavior unique to asyncjs? – Muhammad Umer Apr 13 '15 at 02:27
  • For promises... the rule is that THE function should receive callback as last parameter and must invoke that callback with err as first parameter, right? ..however, on their side i see examples like `Promise.promisify('request'); Promise.promisify('fs'); Promise.promisify('mongoose');` etc. Do those all modules/libraries, by some coincidence, follow these requirements. – Muhammad Umer Apr 13 '15 at 02:32
  • 1
    @MuhammadUmer That is a very misleading example of using the `async` lib. Functions passed to `async.series` are expected to only take a single argument, the callback. Those functions will _never_ get an `err` argument. – Aaron Dufour Apr 13 '15 at 15:09
  • 1
    @MuhammadUmer It is not a coincidence that those libs all follow that convention; it is a strong convention that all of the standard libraries use, so not using it means your code won't play well with anyone else's. – Aaron Dufour Apr 13 '15 at 15:11
4

The promisifyAll() method promisifies the entire module or object which is being called as a parameter. What it means is that a copy of each property of the object is created with Async suffix, which is actually a promisified version of the same method, i.e you can use the .then() or .done() methods on it .

For example, if you have a doSomething() method in someModule module, after calling Promise.promisifyAll(someModule) a new method will be created in the module called doSomethingAsync(). You can use it this way:

var someModule = require('some-module');
Promise.promisifyAll(someModule);
someModule.doSomethingAsync().then(function(result) {
    // do whatever you want with result, this function runs after doSomthingAsync() 
    // is finished and the returned value is stored in 'result' variable.
});

Check out the bluebird API documentation for more information.

Lior Erez
  • 1,852
  • 2
  • 19
  • 24
  • i know what the ending result is but what i want to know is how exactly? Promises rely on internal calls and somehow pass error so you can do `.catch` ...so doSOmething() is not showing any of that working. – Muhammad Umer Apr 13 '15 at 02:22