make node.js fs.readFile as promised action using Q - node.js

when I use deferred.resolve way to promise a action,I can't get the content of the file
function readFile(fileName) {
var deferred = Q.defer();
fs.readFile(fileName, 'utf-8', deferred.resolve);
return deferred.promise;
};
readFile('test.txt').then(function (err, data) {
console.log('data:' + data)
})
I get data:undefined output
but it works OK fine when I promised action httpGet
var httpGet = function (opts) {
var deferred = Q.defer();
http.get(opts, deferred.resolve);
return deferred.promise;
};
httpGet('http://www.google.com').then(function (res) {
console.log("Got response: " + res.statusCode);
res.on('data', function (data) {
console.log(data.toString());
})
}
);
Is there something wrong the code above and in this way how can i get the content of the file.
or is there something different between fs.readFile and http.get?

You can use Q.nfcall to call a NodeJS function promisified.
function httpGet(opts){
return Q.nfcall(http.get,opts);
}
Or simply:
var httpGet = Q.nfbind(http.get,http)
This would also work for fs.readFile by the way.
If you want to do it manually. Q's deferred objects have a .makeNodeResolver function which lets you pass them around safely like you do:
var httpGet = function (opts) {
var deferred = Q.defer();
http.get(opts, deferred.makeNodeResolver());
return deferred.promise;
};
One of the things .makeNodeResolver does is bind the .this value.
It is better to use .nfcall though.

Related

Pulling a value from Asynchronus Function

I'm working with we sockets and I have a lot of requests, so I figured it'd be best to pull the data out of the asynchronus funtion and put it in a variable outside of it. My code looks like this but I just get request [Pending]:
var variable;
var Request = require("request");
function getAsyncValue() {
return new Promise((resolve, reject) => {
Request.get(url, (error, response, body) => {
if(error) {
return reject(err);
}
var object = JSON.parse(body);
var value = object.data.available_balance;
resolve(value);
});
});
}
async function asyncWrapper() {
variable = await getAsyncValue();
return(variable);
}
printVariable = asyncWrapper();
console.log(printVariable);
Any idea on how I can achieve my goal?
Your asyncWrapper is a promise. You have to use await.
To use an await, you need an async function. So you can use a IIFE(Immediately Invoked Functions Expressions) async function.
async function(){
printVariable = await asyncWrapper();
console.log(printVariable);
}();
This was what I was looking for:
var request = require('sync-request');
var returnCode;
var getUrl = "url";
returnCode = httpGet(getUrl);
var object = JSON.parse(returnCode);
var balance = objekt.data.available_balance;
console.log(balance);
function httpGet(url){
var response = request(
'GET',
url
);
return response.body;
}
put your console.log inside the asyncWrapper() as following:
async function asyncWrapper() {
variable = await getAsyncValue();
console.log(printVariable);
return(variable);
}
printVariable = asyncWrapper();
the reason for doing this is because when u had console.log() after the asyncWrapper(), it will be called immediately and not in an sync manner as u would need.
or you can do the following:
Just wrap the asyncWrapper function call inside an another async method and await for the result of asynWrapper() in that. Look below:
var function1 = async function () {
printVariable = await asyncWrapper();
console.log(printVariable);
}

make function wait for a promise to return nodejs

I am using Q library and would like to make the promise2 function to wait until the promise1 function has finished execution.
In the following example the promise2 function gets executed before the promise1 function finishes execution.
What am I doing wrong here?
var Q = require("q");
var fs = require('fs');
function promise1() {
var deferred = new Q.defer();
fs.readFile('hostname.json', function (err, data) {
if (err){
return console.error(err)
}else {
console.log('file read');
return deferred.resolve(JSON.parse(data));
}
});
return deferred.promise;
}
function promise2(){
var deferred = new Q.defer();
var path = 2;
console.log("2");
return deferred.resolve(path);
}
Q(promise1())
.then(promise2());
here is the working example, might give errors since the readfile does not exist, but it does exists in my dev environment.
I get the following result when I run:
>2
>file read
Result I want:
>file read
>2
When you write promise2() you execute it immediately. Try:
promise1().then(promise2);

Async.series: Variable is undefined outside of function

I'm new to Node/Javascript and trying to grab a url audioLink by loading another url songLink. I would then add them to a new object rapSong. To achieve this I am using async series so that the calls will be happen asynchronously. I have tried other methods such as using async waterfall and just callbacks with no success.
audioLink is undefined unless I am within the getAudioLink function. Also the functions in the async.series do not run in the correct order. Any advice?
//for each song..
songLinkElem.each(function(i, s) {
var songName = StringUtils.removeWhiteSpacesAndNewLines($(s).children(".title_with_artists").text());
var songLink = $(s).attr("href");
var audioLink;
async.series([
function(callback){
function getAudioLink(songLink, callback){
request(songLink, function(err,resp,body){
$ = cheerio.load(body);
var audioElem = $(body).find(".audio_link > a");
var audioLink = audioElem.attr("href");
return callback(audioLink);
});
}
getAudioLink(songLink, function(resp){
audioLink = resp;
console.log("one");
})
console.log("two");
callback();
},
function(callback){
var rapSong = new Song(songName, artistLink, songLink, audioLink);
rapArtist.addSong(rapSong);
console.log("three");
callback();
}],
function(err, result){
console.log("four");
});
Within your first async.series function, you shouldn't call its callback until the callback for getAudioLink is called.
So move the code that follows the getAudioLink call inside its callback:
getAudioLink(songLink, function(resp){
audioLink = resp;
console.log("one");
console.log("two");
callback();
});
That way the async.series won't proceed until after audioLink is set.

how to turn an async node function to a promise

I have this async function that I want to turn into a promise
var myAsyncFunction = function(err, result) {
if (err)
console.log("We got an error");
console.log("Success");
};
myAsyncFunction().then(function () { console.log("promise is working"); });
and I get TypeError: Cannot call method 'then' of undefined.
What is wrong with this code?
There are various ways in Q:
Q.nfcall(myAsyncFunction, arg1, arg2);
Q.nfapply(myAsyncFunction, [arg1, arg2]);
// Work with rusable wrapper
var myAsyncPromiseFunction = Q.denodeify(myAsyncFunction);
myAsyncPromiseFunction(arg1, arg2);
in Deferred implementation:
var myAsyncPromiseFunction = deferred.promisify(myAsyncFunction);
myAsyncPromiseFunction(arg1, arg2);
One notable difference: Wrappers as generated by Deferred additionally auto-resolve promises passed as an arguments, so you can do:
var readFile = deferred.promisify(fs.readFile);
var writeFile = deferred.promisify(fs.writeFile);
// Copy file
writeFile('filename.copy.txt', readFile('filename.txt'));
myAsyncFunction return nothing(undefined actually) in your code.
If you use whenjs, the normal way will be like this:
var myAsyncFunction = function() {
var d = when.defer();
//!!!do something to get the err and result
if (err)
d.reject(err);
else
d.resolve.(result);
//return a promise, so you can call .then
return d.promise;
};
Now you can call:
myAsyncFunction().then(function(result(){}, function(err){});

Promise with q framework and the callback pattern in Node.js?

Even if well documented q framework is quite hard to understand if you are programming with Node.js for a few days. But I like to learn about it!
var Q = require('q');
var fs = require('fs');
// Make the promise manually (returns a value or throws an error)
var read1 = fs.readFile(fname, enc, function (err, data) {
if(err) throw err;
return data;
});
// Convenient helper for node, equivalent to read1?
var read2 = Q.nfbind(fs.readFile);
// Uh?!
var read3 = function (fname, enc) {
var deferred = Q.defer();
fs.readFile(fname, enc, function (error, text) {
if (error) {
deferred.reject(new Error(error));
} else {
deferred.resolve(text);
}
return deferred.promise;
});
};
// Execute
Q.fncall(read1).then(function (data) {}, function (err) {}).done();
Are read1, read2 and read3 equivalent? Can I use Q.nfbind every time the last parameter of a function accept a callback in the style of function (err, value)?
You have a few errors in your examples.
read1
This is not 'make a promise manually', this is just making a normal asynchronous call. In your code, you call readFile immediately, so read1 would be the return value of readFile which is undefined. To get a behavior similar to read2 and read3 you would need to do something like this:
var read1 = function(fname, env, success, error){
fs.readFile(fname, enc, function (err, data) {
// Throwing here would just crash your application.
if(err) error(err);
// Returning from inside 'readFile' does nothing, instead you use a callback.
else success(data);
});
};
read2
// Not equivalent to read1 because of the notes above,
// Equivalent to read3, with the fixes I mention below.
var read2 = Q.nfbind(fs.readFile);
read3
var read3 = function (fname, enc) {
var deferred = Q.defer();
fs.readFile(fname, enc, function (error, text) {
if (error) {
// 'error' is already an error object, you don't need 'new Error()'.
deferred.reject(error);
} else {
deferred.resolve(text);
}
// HERE: Again returning a value from 'readFile' does not make sense.
return deferred.promise;
});
// INSTEAD: Return here, so you can access the promise when you call 'read3'.
return deferred.promise.
};
You can indeed use nfbind on anything that takes a callback as the last parameter.
With my comments, read2 and read3 accomplish the same goal, which is to create a function that will take a filename and encoding, and return a promise object.
For those, you can do this:
read2('file.txt', 'utf8').then(function (data) {}, function (err) {}).done();
read3('file.txt', 'utf8').then(function (data) {}, function (err) {}).done();
For read1, you would call it like this:
read1('file.txt', 'utf8', function (data) {}, function (err) {});
Update
Standard promises have evolved a bit since this was answered, and if you are leaning toward read3, I'd recommend doing the following:
var read4 = function (fname, enc) {
return Q.promise(function(resolve, reject){
fs.readFile(fname, enc, function (error, text) {
if (error) {
// 'error' is already an error object, you don't need 'new Error()'.
reject(error);
} else {
resolve(text);
}
});
});
};
This is more in line with standard ES6 promises, and with bluebird, so you'll have an easier time with the code moving forward. Using the method mentioned in read3 also introduces the possibility of synchronously throwing exceptions instead of capturing them in the promise chain, which is usually undesirable. See the deferred antipattern.

Resources