0

say I have the following function which has a synchronous filesystem call enclosed:

var foo = function(){

var numbytes = fs.readSync(...);

return numbytes;
}

no problems there.

but if I use an async function with a callback like so:

var baz = function(){

var numbytes = fs.read(...,function(){

//   return numbytes; (wrong)
});

 //return numbytes; (wrong)
};

how do I properly return a value tied to numbytes from the baz function?

In the Meteor Node.js framework, this might be one answer to this problem:

Meteor.wrapAsync(func, [context]) Anywhere

Wrap a function that takes a callback function as its final parameter. On the server, the wrapped function can be used either synchronously (without passing a callback) or asynchronously (when a callback is passed). On the client, a callback is always required; errors will be logged if there is no callback. If a callback is provided, the environment captured when the original function was called will be restored in the callback.
Arguments

func Function

    A function that takes a callback as its final parameter
context Object

    Optional this object against which the original function will be invoked
Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
  • there must be some sort of design pattern to solve this common problem – Alexander Mills Feb 20 '15 at 09:10
  • 1
    You cannot. You must use a callback (and yes, that's a common pattern) – Bergi Feb 20 '15 at 09:12
  • 1
    That question deals with Ajax calls, but the principle is the same – James Thorpe Feb 20 '15 at 09:12
  • 1
    @JamesThorpe.. its not a duplicate.. though the solution is same for both, **the Question is not a duplicate** – Naeem Shaikh Feb 20 '15 at 09:25
  • @NaeemShaikh Sorry, have to disagree here. From the [dupe help pages](http://stackoverflow.com/help/duplicates) - "There are many ways to ask the same question", and this is fundamentally the same question. – James Thorpe Feb 20 '15 at 09:30
  • @JamesThorpe.. Np.. its all your choice to decide whether to flag this as a duplicate – Naeem Shaikh Feb 20 '15 at 09:32
  • this is a duplicate but not a duplicate, since it's asking about back-end javascript instead of front-end, just leave it, thanks – Alexander Mills Feb 20 '15 at 19:33
  • marking this question as a duplicate was a dick move - sometimes similar questions asked several years later have new answers given the existence of new software libraries. this question is cleaner than the 'original' and asks specifically about node.js not AJAX. – Alexander Mills Mar 26 '15 at 07:37

1 Answers1

1

The normal way to handle this is to make the outer function into an asynchronous function as well. If you don't have control over the lifecycle of the calling function, but do have control over where its return value is used later, you can use a promise to represent the future value of the internal async function, and "unwrap" that promise when needed.

For example, using the Bluebird promises library:

var fs = require("fs");
var Promise = require("bluebird");

var baz = function(){

    var promise = new Promise(function(resolve, reject){
        fs.readFile("file.json", function(err, val) {
            if (err) {
                reject(err);
            }
            else {
                resolve(val);
            }
        });
    });
    return promise;
});


var bazPromise = baz();
bazPromise.then(function(value){
    // deal with value
}, function(error){
    // deal with error
});
Phssthpok
  • 1,629
  • 1
  • 14
  • 21
  • You cannot "unwrap" a promise to a non-promise. If the calling function doesn't expect any asynchrony, you're simply screwed. – Bergi Feb 20 '15 at 10:36
  • Sure, you can't access the future value before it is fulfilled, but you can access it eventually, and it may the case be that processing it in a closure you provide elsewhere solves your problem. Lots of times you have to work with frameworks and inversion-of-control structures that will let you pass an arbitrary value around, and I think the "wrapping" metaphor is appropriate for those situations. – Phssthpok Feb 20 '15 at 10:40