How to pass argument to "then" function - javascript

I'm trying to learn using deferred and I'm stumbled as I'm not getting expected arguments in the "then" block.
var makeCall = function (err, param) {
var deferred = Q.defer();
setTimeout(function() {
console.log(1111, err, param);
deferred.resolve(err, param);
}, 1000);
return deferred.promise;
};
makeCall('test', '11').then(function(err, data) {
console.log(222, err, data);
});
Console. with 1111 outputs correct data that was returned from an Ajax call but 222 does not.
http://jsfiddle.net/M2V44/

deferred.resolve can accept only one argument and that is to mark the success of the asynchronous call. To notify of the failure, you need to use deferred.reject. So your code has to be changed like this
var makeCall = function(err,param){
setTimeout(function () {
console.log(1111, err, param);
var deferred = Q.defer();
if (err) {
deferred.reject(err);
} else {
deferred.resolve(param);
}
}, 1000);
return deferred.promise;
};
makeCall(undefined, '11').then(function (data) {
console.log(222, data);
}, function (err) {
console.log(333, err);
});
This will print 222 '11', to simulate the failure case, just invoke makeCall with any Truthy value as the first argument, for example
makeCall('11')....
it will invoke the failure handler, and the output will be 333 '11'.

In your case, I'd avoid the deferred altogether.
var makeCall = function(err,param){
if(err) return Q.reject(err);
return Q(param).delay(1000);
};
(fiddle)
The usage is similar to thefoureye's answer from earlier, since promises are like synchronous code, you interact with them using return values and catch statements. Nodebacks ((err,data)) and callbacks more generally remove many desirable properties from asynchronous code, and promises aim to restore those properties.
makeCall(new Error("Hello"),"SomeValue").then(function(cata){
console.log("Got correct data!",data);
}).catch(function(err){
console.log("Got error :(",err); // this would happen since we passed an error.
});
I also assume that that this function is imaginary, and not representative of a real API.
You mainly use deferred objects when converting an API to promises, which you don't need to in this case.

Note, a) Not certain if interpret Question correctly; b) Promise appear not implemented universally same in every browser, nor at jsfiddle. This may be helpful JavaScript Promises http://www.html5rocks.com/en/tutorials/es6/promises/ (where below piece can be tried at console; should also work at mozilla nightly console, which appear to implement Promise object)
Try this (pattern)
var makeCall = function(err, param) {
return new Promise(function(resolve, reject ) {
setTimeout(function() {
console.log(1111, err, param);
return (err && param) ?
resolve(err, param) :
reject(Error("error"))
})
}, 1000);
};
makeCall("test", "11")
.then(function(result) {
console.log(222, result);
makeCall("test2","11");
makeCall("abc", 123) // `chain` test
},
function(err) {
console.log(err)
});

Related

Directory check returning false in node.js

I'm having an issue with a Node.js function. I'm fairly certain that it is just an issue with the function being asynchronous but I want to be sure. I am checking to see if a certain path that was entered by the user is valid by checking if it exists.
var directoryExists = exports.directoryExists = function(filePath) {
return new Promise(function(resolve, reject) {
if (fs.statSync(filePath).isDirectory()){
resolve("Valid");
} else {
reject("Invalid");
}
});
}
These are my calls to the function:
files.directoryExists(sourcePath).then((msg) => {
console.log(msg);
}).catch(function(){
console.error("Promise Rejected");
});
files.directoryExists(destPath).then((msg) => {
console.log(msg);
}).catch(function(){
console.error("Promise Rejected");
});
I'm very new to the whole concept of asynchronous programming and promises so this is becoming quite frustrating. Any help would be appreciated.
It's not really the asynchronous thing that's catching you out, although there's a change you can make to improve that.
statSync can throw an exception (if the path doesn't match anything, for instance); you're not handling that, and so when it throws, that gets converted into a rejection. If you looked at the argument you're getting in your catch handler, you'd see the exception that it raises.
The async improvement is that since you're using a Promise, there's no reason to use statSync. Just use stat so you don't tie up the JavaScript thread unnecessarily.
So something along the lines of:
var directoryExists = exports.directoryExists = function(filePath) {
return new Promise(function(resolve, reject) {
// Make the request asynchronous
fs.stat(filePath, function(err, data) {
// If there was an error or it wasn't a directory...
if (err || !data.isDirectory()) {
// ...reject
reject(err || new Error("Not a directory");
} else {
// All good
resolve(data);
}
});
});
};
Of course, you may choose to have it resolve with false if the thing isn't a directory or any of several other choices; this just gets you further along.
For instance, having an error still be a rejection, but resolving with true/false for whether something that exists is a directory; this provides the maximum amount of information to the caller but makes them work a bit harder if all they care about is true/false:
var directoryExists = exports.directoryExists = function(filePath) {
return new Promise(function(resolve, reject) {
// Make the request asynchronous
fs.stat(filePath, function(err, data) {
if (err) {
// Reject on error
reject(err);
} else {
// Return result on success
resolve(data.isDirectory());
}
});
});
};
or making it always resolve, with false if there's no match or there is a match but it's not a directory:
var directoryExists = exports.directoryExists = function(filePath) {
return new Promise(function(resolve) {
// Make the request asynchronous
fs.stat(filePath, function(err, data) {
resolve(!err && data.isDirectory());
});
});
};
Lots of ways for this function to behave, it's up to you.

Make javascript function with callback/promise implementation to always return a promise

I'm trying to have an async authentication handler which can have an implementation with a callback or promises. The scope is to wrap this function in order to always return a promise, so I can use it further callback/promise agnostic.
I would be most grateful if someone could provide some help with these scenarios, one of the examples is real life.
What if the function is something like :
function getData(id, callback) {
var deferred = Q.defer();
apiCall('/path/to/id', function (err, data) {
if (err) deferred.reject(new Error(err));
//do something with data
deferred.resolve(processedData);
}
deferred.promise.nodeify(callback);
return deferred.promise;
}
and I want to use the .fromCallback in this manner
function myProcessedDataFunction(id) {
return Promise.fromCallback(function (callback) {
return getData(id, callback);
}, {multiArgs: true});
}
Will this work ? Will myProcessedDataFunction return a correct promise ?
A real world example is:
I have an authentication handler which might or might not be implemented with a callback function, and at the same time could be implemented using promises; or it might return a true/false value;
function authHandlerImplementation1(username, password) {
return (username === 'validUsername' && password === 'validPassword');
}
function authHandlerImplementation2(username, password, callback) {
apiCall('/path/to/authorization', function (err, result) {
if (err) return callback(err, null);
callback(null, result);
});
}
function authHandlerImplementation3(username, password) {
return new Promise(function (reject, resolve) {
apiCall('/path/to/authorization', function (err, result) {
if (err) return reject(err);
resove(result);
});
});
}
function authHandlerImplementation4(username, password, callback) {
var deferred = Q.defer();
apiCall('/path/to/id', function (err, data) {
if (err) deferred.reject(new Error(err));
//do something with data
deferred.resolve(processedData);
}
deferred.promise.nodeify(callback);
return deferred.promise;
}
I will try a bluebird implementation for 5th one.
function authHandlerImplementation5(username, password, callback) {
return apiCall('/path/to/id', callback).asCallback(callback); // I hope this is the right way to do it (correct me if I'm wrong, please)
}
and my checkAuth function uses the authHandler Implementation and wants to be callback/promise agnostic.
function checkAuth(username, password) {
var self = this;
return Promise.fromCallback(function(callback) {
return self.authHandler(username, password, callback);
}, {multiArgs: true});
}
In case the authHandlerImplementation does not use callbacks (just returns a value) (implementation1), the checkAuth hangs, nothing happens, my tests fail.
Is there any Bluebird method that can wrap any kind of authHandler Implementation into a promise (be it simple return, callback or promise implementation)?
No, Bluebird has no such utility. Supporting both callbacks and promises is nice if you provide them as an API, but not when you need to consume an API - distinguishing whether the method takes callbacks or returns promises or both is not possible from outside, and writing code that figures it out dynamically (on every call) might be possible but awkward.
Bluebird does have a utility that wraps function which might return, throw or return a promise, it's called Promise.method (and there's also Promise.try which immediately invokes it).
I would recommend to force your callers to use promises if they want to pass an asynchronous auth-handler. If they only have a callback-based one, they still can wrap it in Promise.promisify themselves before making it available to you.
I tried some stuff around and I've managed to make it work. I will provide detailed information of the methods I've tried, below. The scenario is for a json-rpc 2.0 server implementation which receives an authHandler function implementation for checking the validity of the provided credentials in a request.
Update:
Using Promise.method on the authHandler var promisifiedAuthHandler = Promise.method(self.authHandler); works for the synchronous implementation of the authHandler.
Fails for the callback implementation.
Using Promise.promisify on the authHandler wrapped in the Promise.method works for the callback implementation var promisifiedAuthHandler = Promise.promisify(Promise.method(self.authHandler));.
Fails for the synchronous implementation.
Providing a callback for the authHandler (even if it does not use it in the implementation) works for all methods. It goes like this (writing for a general case, and this is part of a module written using ES5-Class node module):
function _checkAuth(req) {
var self = this;
var credentials = self._getCredentials(req);
var promisifiedAuthHandler = Promise.method(self.authHandler); // for the sync implementation
switch (authType) {
// general case, let's say, there are several types
// will just write one as an example.
case Authorization.WHATEVERTYPE:
return promisifiedAuthHandler(credentials, function callback(err, result) {
if (err) return Promise.reject(err);
return Promise.resolve(result);
}
}
}
and the server.enableCookie/JWT/BasicAuth handler can be implemented in the three ways mentioned: sync/callback/promise; As follows:
server.enableCookieAuth(function (cookie) {
return (cookie === validCookieValue);
});
server.enableCookieAuth(function (cookie, callback) {
apiCall('path/to/auth', function(err, result) {
// apiCall could have a promise implementation, as well, and could
// be used with .then/.catch, but this is not that important here, since we care
// about the handler implementation)
if (err) return callback(err, null);
callback(null, result); // can be returned
}
});
server.enableCookieAuth(function (cookie) {
// let's write the apiCall with promise handling, since we mentioned it above
return apiCall('path/to/auth').then(function (result) {
return Promise.resolve(result);
}).catch(function (err) {
return Promise.reject(err);
});
});
Now, we can use our _checkAuth function internally using only promises, agnostic of the authHandler function implementation. As in:
handleHttp: function(req, res) {
var self = this;
// ...other processing
self._checkAuth(req).then(function (result) {
// check if the user is authed or not
if (result) {
// further process the request
} else {
// handle unauthorized request
}
}).catch(function (err) {
// handle internal server or api call (or whatever) error
});
}
The trick was to write our callback with a promise implementation. We always provide the authHandler a callback implementation, even if the authHandler does not use it. This way, we always make sure that the auth handler implementation returns a promise if it uses a callback style implementation.
All comments are welcomed and I would like to hear some opinions on this matter!
Thank you for your prompt responses!

Chek the return from a promise function before proceeding. Wrong approach?

Background: I have a PHP background and this is my first application using MEAN stack.
I need to save a record but before I must to check if there is any record under the same id already saved in the DB.
In PHP I would do something like this:
Once the user clicks "Save":
1) Call the function to check if an entry with that id already exists
2) If it doesnt, call the save function.
In Javascript, I'm getting a little confused with Promises and so on.
Can somebody give me some light here?
Right now, I'm doing the following:
In the save api, I call this function to check if the record already exists in the DB:
recordExists = findTranscationByBill(billId);
function findTransactionByBill(billId){
results = new promise(function(resolve, reject){
Transactions.find({billId : billId},function(err, transactions){
if(err)
reject("Error: "+err);
//console.log(transactions);
resolve(transactions);
});
});
results.then(function(data){
console.log('Promise fullfilled: '+ data);
}, function(error){
console.log('Promise rejected: ' + error);
});
return $results;
}
The problem is that I think I'm not using promise properly, as my variable doesn't get populated (because its Async).
In the console.log I see that the promise is being fulfilled however, the variable returns as [object Object]
I'm stucked with this problem because I don't know if I should carry on thinking as PHP mindset or if there is a different approach used in Javascript.
Thanks in advance!
In my opinion you could just as well use a callback for this, and since MongoDB has a count method, why not use it
function findTransactionByBill(billId, callback){
Transactions.count({billId : billId}, function(err, count){
if (err) {
callback(err, false);
} else {
callback(null, count !== 0);
}
});
}
and to use it
findTransactionByBill(billId, function(err, exists) {
if (err) {
// handle errors
} else if ( ! exists ) {
// insert into DB
}
}
I think the right function is:
function findTransactionByBill(billId){
var results = new promise(function(resolve, reject){
Transactions.find({billId : billId},function(err, transactions){
if(err) {
reject(err);
} else {
if (transactions.length === 0) {
reject('No any transaction');
} else {
//console.log(transactions);
resolve(transactions);
}
});
});
results.then(function(data){
console.log('Promise fullfilled: '+ data);
}, function(error){
console.log('Promise rejected: ' + error);
});
return results;
}
And then use it like this:
recordExists = findTranscationByBill(billId);
recordExists.then(function() {
// resolved, there are some transactions
}, function() {
// rejected. Error or no any transactions found
// may be you need to check reject result to act differently then no transactions and then error
});
I assume you are using mongodb native drive.
I think mongodb doesn't have promise built-in supported. So you have to promisify it by a little help from promise library. Please refer this if you want to use bluebird.
After promisifying, the code should looks like that (using bluebird):
Promise = require('bluebird');
// Promisify...
var _db = null;
var client = MongoClient.connectAsync('mongodb://localhost:27017/test')
.then(function(db) {
_db = db
return db.collection("myCollection").findOneAsync({ id: 'billId' })
})
.then(function(item) {
if (item)
_db.save(item);
})
.catch (err) {
// error handling
}
The above code is not perfect, because it introduced a global var, so the better version may be
Promise = require('bluebird');
// Promisify...
var client = MongoClient.connectAsync('mongodb://localhost:27017/test')
.then(function(db) {
return Promise.prop({
item: db.collection("myCollection").findOneAsync({ id: 'billId' },
db: db
})
})
.then(function(result) {
var item = result.item;
var db = result.db
if (item)
db.save(item);
})
.catch (err) {
// error handling
}
You need to check bluebird to know how to use it. Also they are many other promise libraries like q, when, but all are similar stuff.

Creating promises

I am having trouble with creating / understanding promises. I understand the advantages and understand how to use them. Creating own promise-functionality is the difficult part. Simply, how do I convert this function to work with promises:
ret.getDataByGame = function (gameID, playerID) {
var cb = new callbackHelper();
models.gameData.find( { }, function (err, found) {
if (err) {
console.log("error in getting gamedata for gameID: "+gameID);
cb.setData(void 0);
} else {
cb.setData(found);
}
});
return cb;
};
function callbackHelper() {
var self = this;
this.data = false;
this.setData = function (data) {
self.data = data;
};
It should not matter what framework or vanilla js you use to show the example to me.
ret.getGameDataByGame = lib.promisify(models.gameData.find);
might suffice. Or use a dedicated node-style callback helper function:
ret.getGameDataByGame = function(gameID, playerID) {
return lib.ninvoke(models.gameData, "find", {…});
};
For the Q library, check the Adapting Node section of its docs.
For creating a promise with the pattern you've used for your callbackHelper thing, your promise library typically offers Deferreds. You would use them like this:
ret.getDataByGame = function (gameID, playerID) {
var def = new lib.Deferred();
models.gameData.find({…}, function (err, found) {
if (err) {
def.reject("error in getting gamedata for gameID: "+gameID);
} else {
def.fulfill(found);
}
});
return def.promise;
};
See also the The Beginning section in the Q docs.
Just to give a second input, I quickly looked at the promise implementation of Q docs, but this is the implementation that I use, which is supported by default, in browsers (except IE). With respect to your posted algorithm:
//define promise structure for callback function of interest
ret.getDataByGame = function(gameID, playerID){
return new Promise(function(resolve,reject)
{
try
{
//do any callback function etc. which you want to do
models.gameData.find({},function(err, found){
if(err)
{
console.log("error in getting gamedata for gameID: "+gameID);
reject(err); //if there is error, save as reject
}
else
resolve(found); //if have solution, save as resolve
}
}
catch(exc)
{reject('Error exc gameData.find: '+exc.message);}
}); //end of Promise
}
And then where you call your class functions etc.:
//where you physically call the function you defined as a promise function
ret.getDataByGame('input1','input2').then(function(output){
alert("woohoo, you are awesome!, output = "+output);
},function(error){
alert("Output error:\r\n"+error);
});
Here is the definition and implementation of promises which I consider as the "standard" thus far, with browser support versions: Promise doc + tutorial. An the cool thing if you do it for massive amounts of data, and they are async, you really optimize your execution time!! such as:
//repeat promise function
function repeatPromise(inputDataArray)
{
for(var i = 0; i < inputDataArray.length; i++)
{
//where you physically call the function you defined as a promise function
ret.getDataByGame(inputDataArray[i].input1,inputDataArray[i].input2).then(function(resolve){
alert("Output is in async, output = "+resolve);
},function(error){
alert("Output error:\r\n"+error);
});
} //end of for loop
} //end of function
Hope this helps :)

Serial execution with Q promises

I think I'm misunderstanding how Q promises work. I want my first promise to resolve before the next one starts, but that's not happening. Here is my code:
var Q = require('q');
function doWork(taskName) {
var deferred = Q.defer();
console.log('starting', taskName);
setTimeout(function() {
console.log('done with', taskName);
deferred.resolve();
});
return deferred.promise;
}
doWork('task one')
.then(doWork('task two'))
.then(function() { console.log('all done'); });
This code produces:
$ node test.js
starting task one
starting task two
done with task one
done with task two
all done
I would hope that it produces:
$ node test.js
starting task one
done with task one
starting task two
done with task two
all done
What am I doing wrong?
This works:
doWork('task one')
.then(function() {
return doWork('task two')
})
.then(function() {
console.log('all done');
});
That makes sense - just calling doWork directly in then() will fire off the timeout immediately, instead of giving Q a chance to wait until task one is complete.
The reason is that the doWork needs to be referenced as a function. If you want to reference a function inside the '.then' then you just give the function name, you don't pass the parameters. When the parser sees .then(doWork('taskTwo'))it will run doWork('taskTwo') BEFORE the .then is even evaluated. It's trying to bind the function parameter.
In this case, if you return the parameter for the next task in the resolved promise of the previous task then the parser will call doWork with the correct parameter and in the correct order.
var Q = require('q');
function doWork(taskNum) {
var deferred = Q.defer();
console.log('starting', taskNum);
setTimeout(function() {
console.log('done with task', taskNum);
deferred.resolve(++taskNum);
});
return deferred.promise;
}
doWork(1)
.then(doWork)
.then(function(lastTaskNum) { console.log('all done'); });
Sample code using q and request
var Q = require('q'),
request = require('request'),
api = {};
api.post = function (options) {
var deferred = Q.defer();
request.post(options, function (error, response, body) {
error ? deferred.reject(error) : deferred.resolve(body);
});
return deferred.promise;
};
api.get = function (options) {
var deferred = Q.defer();
request.post(options, function (error, response, body) {
error ? deferred.reject(error) : deferred.resolve(response);
});
return deferred.promise;
}
api
.post({url: 'https://foo.com'})
.then(function (body) {
console.log(body);
return api.get({url: 'http://myspace.hell'});
}, function (error) {
//error handling logic
})
.then(function (response) {
console.log(response);
}, function (error) {
//error handling logic
})
.done(); //when you are done
In the code above, you can see that I define 2 API methods: get and post.
I'm using the request library.
my post api method, resolves the promise with the body of response object returned by request.post()
my get api method, resolves the promise with the response of the request.get() call
You can see exactly how you can chain these 2 api call using the promises.
In the first then I return the second promise, so that I can chain the promise.

Categories

Resources