Serial execution with Q promises - javascript

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.

Related

returning data in node js

I have two files in my application,
DesignFactory.js:
var fs = require('fs');
var dotenv = require('dotenv');
dotenv.load();
var designtokenfile = require ('./designtokenfile');
var designtokendb = require ('./designtokendb');
var TYPE=process.env.TYPE;
var DesignFactory={};
DesignFactory.storeDesign = function(TYPE) {
if (TYPE == 'file') {
var data=design.designtokenfile.load();
console.log(data);
} else if (TYPE == 'db') {
return designtokendb;
}
};
module.exports.design=DesignFactory;
now, I have another designtokenfile.js file,
designtokenfile.js:
var fs = require('fs');
var load = function() {
fs.readFile('output.txt', 'utf8', function (err,data) {
return data;
if (err) {
return console.log(err);
}
});
};
module.exports.load=load;
So my problem is am not able get data returned from load method. when I print data inside storeDesign method returned from load function, it displays undefined.
but I want contents of output.txt inside storeDesign method.
Please help me.
Instead of:
var load = function() {
fs.readFile('output.txt', 'utf8', function (err, data) {
return data;
if (err) {
return console.log(err);
}
});
};
which has no way of working because the if after the return would never be reached, use this:
var load = function(cb) {
fs.readFile('output.txt', 'utf8', function (err,data) {
if (err) {
console.log(err);
return cb(err);
}
cb(null, data);
});
};
and use it like this:
load((err, data) => {
if (err) {
// handle error
} else {
// handle success
}
});
Or use this:
var load = function(cb) {
return new Promise(resolve, reject) {
fs.readFile('output.txt', 'utf8', function (err, data) {
if (err) {
console.log(err);
reject(err);
}
resolve(data);
});
});
};
and use it like this:
load().then(data => {
// handle success
}).catch(err => {
// handle error
});
In other words, you cannot return a value from a callback to asynchronous function. Your function either needs to tak a callback or return a promise.
You need to reed more about asynchronous nature of Node, about promises and callbacks. There are a lot of questions and answers on Stack Overflow that I can recommend:
promise call separate from promise-resolution
Q Promise delay
Return Promise result instead of Promise
Exporting module from promise result
What is wrong with promise resolving?
Return value in function from a promise block
How can i return status inside the promise?
Should I refrain from handling Promise rejection asynchronously?
Is the deferred/promise concept in JavaScript a new one or is it a traditional part of functional programming?
How can I chain these functions together with promises?
Promise.all in JavaScript: How to get resolve value for all promises?
Why Promise.all is undefined
function will return null from javascript post/get
Use cancel() inside a then-chain created by promisifyAll
Why is it possible to pass in a non-function parameter to Promise.then() without causing an error?
Implement promises pattern
Promises and performance
Trouble scraping two URLs with promises
http.request not returning data even after specifying return on the 'end' event
async.each not iterating when using promises
jQuery jqXHR - cancel chained calls, trigger error chain
Correct way of handling promisses and server response
Return a value from a function call before completing all operations within the function itself?
Resolving a setTimeout inside API endpoint
Async wait for a function
JavaScript function that returns AJAX call data
try/catch blocks with async/await
jQuery Deferred not calling the resolve/done callbacks in order
Returning data from ajax results in strange object
javascript - Why is there a spec for sync and async modules?
Return data after ajax call success
fs.readFile ist asynchrone so you need to pass a callback function or use fs.readFileSync
You are getting undefined because of asynchronous nature.. Try for the following code:
var fs = require('fs');
var load = function(callback) {
fs.readFile('output.txt', 'utf8', function (err,data) {
//return data;
callback(null, data);
if (err) {
callback("error", null);
}
});
};
module.exports.load=load;
var fs = require('fs');
var dotenv = require('dotenv');
dotenv.load();
var designtokenfile = require ('./designtokenfile');
var designtokendb = require ('./designtokendb');
var TYPE=process.env.TYPE;
var DesignFactory={};
DesignFactory.storeDesign = function(TYPE) {
if (TYPE == 'file') {
var data=design.designtokenfile.load(function(err, res){
if(err){
} else {
console.log(data);
}
});
} else if (TYPE == 'db') {
return designtokendb;
}
};
module.exports.design=DesignFactory;

How to use result of first api, into second api call in angularjs?

I want to use the result of first api, into second api call. Scenario is like that, I want to use the result of first api, into second api call. If I am correct then I want synchronous api call(not sure). I tried to write following function but not working. function2 is call before function1. In function2 we are use result1 which is only come when function1 is called before function2, How I do.
$scope.function1 = function(){
var deferred= $q.defer();
$http.post(api1, data1)
.success(function(response, status) {
if (response.error == 0) {
console.log(response.result);
$scope.result1=response.result;
}
}) ;
deferred.resolve('Success') ;
return deferred.promise;
};
var promise = $scope.addDefaultValue();
promise.then(function(){
$scope.function2();
});
$scope.function2=function(){
var deferred = $q.defer();
$http.post(api2,result1)
.success(function(response, status){
if(response.error == 0){
}
});
deferred.resolve('Success') ;
return deferred.promise;
}
You could follow promise chain pattern here, follow chaining using .then on promise object.
No need to create extra overhead promise using $q, as $http methods returns promise object when they start an ajax.
Code
$scope.function1 = function() {
return $http.post(api1, data1)
.then(function(d) {
var response = d.data;
if (response.error == 0) {
console.log(response.result);
$scope.result1 = response.result;
}
return response;
});
};
$scope.function1().then(function(data) {
$scope.function2();
}, function(error) {
});
You cannot convert $http requests to "synchronous". That's not what "deferred" does. Deferred is a way to convert non-promise-capable functions to promise-capable functions. $http functions return promise objects so you don't need to use deferred.
$http.post(api, data1).then(function (response) {
$scope.result1 = response.data.result;
// return is important here
// so that you can keep chaining with .then
return $http.post(api2, response.data.result);
}).then(function (response) {
// here you have response from api2
$scope.result2 = response.data.result;
console.log(response.data);
}).catch(function (error) {
// here you can handle errors
// from either api calls
// second api call won't be made if the first one fails
console.log(error);
});

How to assign multiple onError functions to a promise (returned by angular's $http.post)

My AngularJS code needs to chain multiple onSuccess, onError functions to a promise returned by $http.post
var promise = $http.post(url);
promise
.then(
/*success 1*/function () { console.log("success 1"); },
/*error 1*/function () { console.log("error 1"); })
.then(
/*success 2*/function () { console.log("success 2"); },
/*error 2*/function () { console.log("error 2"); });
The problem with above code is that it prints error 1 > success 2 when the HTTP response fails instead of error 1 > error 2.
I did some research on stackoverflow and found that when you have access to $q you can just do $q.reject() in error 1 to trigger error 2 but in my case i only have access to the promise returned by $http.post. So what do I do?
P.S. Of course, I can call error2() from inside of error 1 but i want to chain them because it looks more readable and extensible.
Any ideas?
Returning a value (or returning no value) from a success/error handler will resolve the promise for the next then block in the chain. To propagate the rejection, return $q.reject():
var promise = $http.post(url);
promise
.then(
/*success 1*/function () { console.log("success 1"); },
/*error 1*/function () { console.log("error 1"); return $q.reject();})
.then(
/*success 2*/function () { console.log("success 2"); },
/*error 2*/function () { console.log("error 2"); });
Your question stems from some misunderstanding of what promises enable - namely, async code composition that parallels that of a synchronous code with try/catch, with proper exception handling.
I am specifically referring to your statement:
"but i want to chain them because it looks more readable and extensible."
as the source of misunderstanding of chaining.
If your example was synchronous (assuming all async calls were blocking), this is likely what you would have wanted to do:
try {
var data = $http.post(url); // blocking
var res1 = doSuccess1(data);
var ret = doSuccess2(res1);
}
catch(e){
errorHandler1(e);
errorHandler2(e);
}
And not this:
try {
try {
var data = $http.post(url);
var res1 = doSuccess1(data);
} catch (e) {
errorHandler1(e);
// throw ""; // this is what returning $q.reject would have done - a rethrow
}
} catch (e) {
errorHandler2(e);
}
var ret = doSuccess2(res1);
which is what you would have achieved with your chaining. In other words, nested try/catch and unhandled exception in doSuccess2.
The following is the async parallel of the first approach:
var ret;
$http.post(url)
.then(function(data){
var res1 = doSuccess1(data);
ret = doSuccess2(res1);
}
.catch(function(e){ // or .then(null, handler)
doError1(e);
doError2(e);
})
And if one of doSuccessN functions were also async:
var ret;
$http.post(url)
.then(doSuccess1Async)
.then(function(res1){
ret = doSuccess2(res1);
}
.catch(function(e){ // or .then(null, handler)
doError1(e);
doError2(e);
})
Just wrap the handlers in a function, in the success / error handler parameters:
var promise = $http.post(url);
promise
.then(function(argX, argY){
success1(argX, argY);
success2(argX, argY);
},
function(argX, argY){
error1(argX, argY);
error2(argX, argY);
});

Node.js Q Promises Multiple Parameters

Trying to cleanup my callback spaghetti code using the Q promise library in my nodejs express app, but I'm having trouble translating some parts of it. Having trouble passing multiple arguments to functions and dealing with the scope.
Here's a simplified "synchronous" version to show my logic:
function updateFacebook(req, res) {
var user = getUserFromDB(userid);
var profile = getUserProfileFromAPI(accessToken);
var success = updateUserDB(user, profile);
res.json({ result: success });
}
So I convert the callback functions to return promises
function getUserFromDB(userid) {
var deferred = Q.defer();
// somewhere in here there's a deferred.resolve(user object);
queryMongo()...
return deferred.promise;
}
function getUserProfileFromAPI(accessToken) {
var deferred = Q.defer();
// somewhere in here there's a deferred.resolve(profile object);
request()...
return deferred.promise;
}
function updateUserDB(user, profile) {
var deferred = Q.defer();
// somewhere in here there's a deferred.resolve(updated user object);
updateMongo()...
return deferred.promise;
}
function handleResponse(res, user) {
var deferred = Q.defer();
// was thinking about putting the res.json here
// i have no way of passing in the res
// and res is out of scope...
res.json({});
return deferred.promise;
}
Now the problem is linking them up, I tried...
Q.when(getUserFromDB(userid), getUserProfileFromAPI(accessToken))
.spread(updateUserDB)
.done(handleResponse);
Q.all([getUserFromDB(userid), getUserProfileFromAPI(accessToken)])
.spread(updateUserDB)
.done(handleResponse);
Super confused. Any direction would be much appreciated.
Looks like your handleResponse is expecting two params, but updateUserDB is only resolving a single object. You could do something like:
function getResponseHandler(res) {
return function(user) {
// your handleResponse code here
// which now has access to res
}
}
and then call it like:
Q.all([getUserFromDB(userid), getUserProfileFromAPI(accessToken)])
.spread(updateUserDB)
.done(getResponseHandler(res));

How to pass argument to "then" function

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)
});

Categories

Resources