Q/Promise handle callback params - node.js

var Q = require("q");
function test(v){
var deferred = Q.defer()
if (v) {
console.log("success");
deferred.resolve();
}
else{
console.log("failed");
deferred.reject(new Error("failed"))
}
return deferred.promise;
}
var over = function(url){
console.log("hahaha")
console.log(url)
}
var failed = function(){
console.log("wuwuw")
}
test().then(over, failed)
test().then(over("localhost"), failed)
When test().then(over, failed), function over should not execute,The program can do well,
I can get the result:
failed
wuwuw
But when I add params for function over, the function over will execute. I will get:
failed
hahaha
localhost
wuwuw
Obviously, I don't want the function over execute, but I need it get the params when test() resolved.

But when I add params for function over, the function over will execute.
That's because you're calling it. You still need to pass a function to then:
test().then(function(testResult) {
over("localhost");
}, failed)

Related

BlueBird Promises returns "Undefined" when return inside "then" function

Here is my Code:
Checking if user is folowing official Twitter Account (here I've returned new Promise
var isFollowing = function(sender) {
return new promise(function(resolve, reject) {
var following = false;
var params = {
source_id: sender,
target_screen_name: config.get('twitter.official_account')
};
TwitObj.get('friendships/show', params, function(err, data) {
if (!err) {
following = data.relationship.source.following;
resolve(following);
} else {
reject(err);
}
});
});
};
Validation:
var validateMsg = function(dm) {
var sender = getSender(dm);
var result = [];
isFollowing(sender.id)
.then(function(response) {
if (!response) {
result = interactiveMessage(false, lang.__('FOLLOW_MAIN', sender.name));
console.log(result); // Displays as expected
return result; // Not returning value Do I need to return promise again? If yes, WHY?
}
});
};
Main Implementation:
var direct_message = function(msg) {
verifyAccount().catch(function(err) {
console.error(err);
});
var dm = msg.direct_message;
var result = validateMsg(dm);
console.log(result);
};
Questions is how should I force validateMsg function to return result variable inside then function.
Update: While debugging, I got to know that, console.log(response) in
validation function is displaying later after throwing undefined in
"then" function which means program is not able to get response
immediately and due to async nature, I/O is not getting blocked. How
to tackle this?
You're not actually returning anything in the validateMsg function. You're returning a synchronous value ( result ) in the .then function which is a separate function.
The second thing to consider is that you're expecting the validateMsg function, which is asynchronous to behave synchronously.
var result = validateMsg(dm);
The way to achieve what I believe you're looking to do involves making the following changes:
1) Return the promise chain in the validateMsg function.
var validateMsg = function(dm) {
var sender = getSender(dm);
var result = [];
return isFollowing(sender.id)
.then(function(response) {
if (!response) {
result = interactiveMessage(false, lang.__('FOLLOW_MAIN', sender.name));
return result;
}
// Not sure what you want to do here if there is a response!
// At the moment you're not doing anything if the validation
// is successful!
return response;
});
};
2) Change your function call, since you're now returning a promise.
validateMsg(dm).then( function( result ){
console.log( result );
})
3) Consider adding a catch somewhere if only to help you debug :)
validateMsg(dm).then( function( result ){
console.log( result );
})
.catch( function( err ){
console.log( "Err:::", err );
});
The validationMsg function does not have a return value, thus the result in the main function has the value undefined. Try to put return in front of isFollowing so the function returns a promise, then treat validationMsg as a promise.

bluebird promisifyAll() and then() not working together with node require

I'm using Promises for the first time, so please bear with me.
Basically, I'm not seeing the function in my .then() statement being called.
When I call t.t(), is it working correctly.
When I call t.tAsync(), t() is again called.
However the result isn't being passed into the then when I call t.tAync().then(console.log);
Here is my node module:
'use strict';
var t = function(){
console.log('inside t()');
return 'j';
};
module.exports = {
t: t
};
And here is my demo script:
'use strict';
require('should');
var Promise = require('bluebird');
var t = require('../src/t');
Promise.promisifyAll(t);
/*
Call t() once to demonstrate.
Call tAsync() and see t() is called
Call tAsync.then(fn), and then isn't called
*/
// this works as expected, calling t()
console.log('calling t()...' + t.t());
// this also works, calling t()
t.tAsync();
// the then() statement isn't called
t.tAsync().then(function(res){
// I expect this to be called
console.log('HHHUUUZZZAAAHHH' + res);
});
/*
Keep the script running 5 seconds
*/
(function (i) {
setTimeout(function () {
console.log('finished program');
}, i * 1000)
})(5);
And here is the output from the test:
inside t()
calling t()...j
inside t()
inside t()
finished program
Your then clause will never be called because the tAsync is expecting t to call the callback not return a value.
promisifyAll wraps Node.JS aysynchronous API's so the function it is wrapping needs to conform to the Node.JS callback signature:
function t(callback) {
callback(null, 'j');
}
However, I suspect based on your code that you do not want promiseifyAll but instead try() or method():
function t() {
return 'j';
}
Promise.try(t).then(function(result) {
console.log(result);
});
OR
var t = Promise.method(function() {
return 'j';
});
t().then(function(result) {
console.log(result);
});
For contrast the above is Bluebird.js specific. To perform this with generic Promises you would approach it one of two ways:
Using the Promise constructor:
function t() {
return new Promise(function(resolve, reject) {
resolve('j');
});
}
t().then(function(result) {
console.log(result);
});
Or, use the then chaining feature:
function t() {
return 'j';
}
Promise.resolve()
.then(t)
.then(function(result) {
console.log(result);
});
I was also not able to understand how "then" works. Below code example (just created to understand the flow) may help you:
var Promise = require('bluebird');
function task1(callback) {
setTimeout(function(){
console.log("taks1");
callback(null, "taks1");
}, 2000);
}
var taks1Async = Promise.promisify(task1);
taks1Async().then(function(result) {
console.log("Current task2, previous: " + result);
return "task2";
})
.then(function(result) {
console.log("Current task3, previous: " + result);
return "task3";
})
.catch(function(e) {
console.log("error: " + e);
});
console.log("Finished");

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.

Clean down the index before each text (Mocha, Elastic)

How do we clear down the index before each test? (at the moment it fails my test, with a timeout)
I have tried
DeleteBy (I have tried the term and q)
http delete
delete the index
I have the following code:
var assert = require("assert"),
elasticsearch = require('elasticsearch'),
request = require('request'),
q = require('q'),
client;
client = new elasticsearch.Client();
describe('people', function(){
beforeEach(function(done){
//is this correct?
//looks like poeple get deleted.
client.deleteByQuery({
index: 'people',
q: '*'
}, function (error, response) {
done();
});
//I have also tried the following:
//this way returns an accept code.
// var deleteOptions = {
// method: 'DELETE',
// uri: 'http://localhost:9200/people/person'
// };
//
// webApi(deleteOptions).then(function(data){
// //{"acknowledged":true}
// console.log(data.body);
// done();
// });
//the following throws an exception
//delete index
// client.indices.delete('people').then(function(del){
// console.log(del);
// client.indices.create('people').then(function(ct){
// console.log(ct);
// done();
// });
// });
});
describe('add a entry into the index', function(){
it('should add Dave as a person to the database', function(done){
//THIS TEST WILL FAIL
//Error: timeout of 2000ms exceeded
//I have tried adding a timeout.
assert.equal(1,1);
});
});
});
var webApi = function(options){
var deferred = q.defer();
var handle = function (error, response, body) {
//console.log(body);
if(error) {
deferred.reject(error);
}
else {
deferred.resolve({response:response, body:body});
}
};
request(options, handle);
return deferred.promise; //NOTE: we now return a promise
};
The test that you marked with THIS TEST WILL FAIL fails with a timeout because you never call done() in it. You've declared the anonymous function you pass to it with a parameter, which tells Mocha that your test is asynchronous (even if the code in it is not asynchronous right now) and thus Mocha waits for done() to be called. You can either call it, or remove the parameter from your function.

async/flow series on node.js

Consider this code:
var async = require('async');
var a = function()
{
console.log("Hello ");
};
var b = function()
{
console.log("World");
};
async.series(
[
a,b
]
);
Output is
Hello
Why is World not part of the output?
The async.series function passes one callback to each of the methods that must be called before the next one is called. If you change your functions a and b to call the function it will work.
function a(done){
console.log('hello');
done(null, null); // err, value
}
function b(done){
console.log('world');
done(null, null); // err, value
}
For each method called in series it is passed a callback method which must be run, which you are ignoring in your example.
The docs say:
tasks - An array or object containing functions to run, each function
is passed a callback(err, result) it must call on completion with an
error err (which can be null) and an optional result value.
The reason why your code is stopping after the first method is that the callback isn't being run, and series assumed an error occurred and stopped running.
To fix this, you have to rewrite each method along these lines:
var b = function(callback)
{
console.log("World");
callback(null, null) // error, errorValue
};

Resources