Bluebird promises in NodeJS, not getting to then - node.js

I'm attempting to use bluebird promises in NodeJs with nano a library used with couchDb. I use the promisfy and when I look get the new async methods. In the following example, the nano.db.listAsync call works out fine, but I never get to the .then or the .catch.
What is wrong here?
var nano = require('nano')(this.appInfo.dbServiceUrlPrefix);
Promise.promisifyAll(nano);
Promise.promisifyAll(nano.db);
var p = nano.db.listAsync(function(err,body) {
// get all the DBs on dbServiceUrlPrefix
var dbNames:string[] = <string[]> body ;
console.log("allDbs",dbNames) ;
return dbNames ;
}).then(function (e:any) {
console.log('Success',e);
}).catch(function(e:any){
console.log('Error',e);
});

There are a couple things wrong.
After promisification and calling the promsified version, you use .then() to get the result.
The .then() resolve handler has no err variable any more. If there's an error, the .then() reject handler is called.
So, I think you want something like this:
var nano = require('nano')(this.appInfo.dbServiceUrlPrefix);
Promise.promisifyAll(nano);
Promise.promisifyAll(nano.db);
nano.db.listAsync().then(function(body) {
// get all the DBs on dbServiceUrlPrefix
var dbNames:string[] = <string[]> body ;
console.log("allDbs",dbNames) ;
return dbNames;
}).then(function (e:any) {
console.log('Success',e);
}).catch(function(e:any){
console.log('Error',e);
});
P.S. Are you sure there are not supposed to be any function arguments passed to nano.db.listAsync()?

I think the function parameters you pass to nano.db.listAsync() are incorrect. It would not have err parameter after promissification, so your code should look something like this:
var nano = require('nano')(this.appInfo.dbServiceUrlPrefix);
Promise.promisifyAll(nano);
Promise.promisifyAll(nano.db);
var p = nano.db.listAsync(function(body) {
...

Related

Firestore onWrite trigger using callback return undefined

i tried to add a trigger function on my cloud functions.
When a document changed i want to perform some work. I have already the code for the work to do in another file (i separate my work into files, so it's get easier for me), so i have a function that performs work and when it is finished the callback is called.
This is what my index.js look like:
// requires...
// Express, i also use express for simulating an API
const app = express()
// So there is my Listener
const listenerForChange = functions.firestore
.document('myPath/documentName')
.onWrite((change, context) => {
const document = change.after.exists ? change.after.data() : null;
if (document != null) {
const oldDocument = change.before.data();
const newDocument = change.after.data()
// Here i call my function that is in the worker-listeners.js
listenerWorker.performStuff(newDocument, function() {
return 0
})
}
else {
console.error("Listener for classic was triggered but doc does not exist")
return 0
}
});
const api = functions.https.onRequest(app)
module.exports = {
api,
listenerForChange
}
...
There is my listenerWorker.js :
module.exports = {
performStuff: function(data, complete) {
performStuff(data, complete)
}
};
function performStuff(data, complete) {
// do stuff here ...
complete()
}
Problem is that i always an error in the Firebase console saying : Function returned undefined, expected Promise or value
Even if i do not do anything inside my worker and calling the callback as soon as i can i get the error.
So i understand the functions needs a response, promise or value. But it's like i'm not in the scope anymore but i do not want to return before the work is finished !
Any help ? thank you guys
All asynchronous work that you perform should be represented by a promise. If you have a utility object that does async work, it should return a promise so that the caller can decide what to do next with it. Right now you're just using callbacks, and that's going to make things much more difficult than necessary (because you'll have to "promisify" those callbacks).
Just use promises everywhere and it'll be much more clear how your function should work.

How to use promise bluebird in nested for loop?

I need to use bluebird in my code and I have no idea how to use it. My code contains nested loops. When the user logs in, my code will run. It will begin to look for any files under the user, and if there are files then, it will loop through to get the name of the files, since the name is stored in a dictionary. Once it got the name, it will store the name in an array. Once all the names are stored, it will be passed along in res.render().
Here is my code:
router.post('/login', function(req, res){
var username = req.body.username;
var password = req.body.password;
Parse.User.logIn(username, password, {
success: function(user){
var Files = Parse.Object.extend("File");
var object = [];
var query = new Parse.Query(Files);
query.equalTo("user", Parse.User.current());
var temp;
query.find({
success:function(results){
for(var i=0; i< results.length; i++){
var file = results[i].toJSON();
for(var k in file){
if (k ==="javaFile"){
for(var t in file[k]){
if (t === "name"){
temp = file[k][t];
var getname = temp.split("-").pop();
object[i] = getname;
}
}
}
}
}
}
});
console.log(object);
res.render('filename', {title: 'File Name', FIles: object});
console.log(object);
},
error: function(user, error) {
console.log("Invalid username/password");
res.render('logins');
}
})
});
EDIT:The code doesn't work, because on the first and second console.log(object), I get an empty array. I am suppose to get one item in that array, because I have one file saved
JavaScript code is all parsed from top to bottom, but it doesn't necessarily execute in that order with asynchronous code. The problem is that you have the log statements inside of the success callback of your login function, but it's NOT inside of the query's success callback.
You have a few options:
Move the console.log statements inside of the inner success callback so that while they may be parsed at load time, they do not execute until both callbacks have been invoked.
Promisify functions that traditionally rely on and invoke callback functions, and hang then handlers off of the returned value to chain the promises together.
The first option is not using promises at all, but relying solely on callbacks. To flatten your code you will want to promisify the functions and then chain them.
I'm not familiar with the syntax you're using there with the success and error callbacks, nor am I familiar with Parse. Typically you would do something like:
query.find(someArgsHere, function(success, err) {
});
But then you would have to nest another callback inside of that, and another callback inside of that. To "flatten" the pyramid, we make the function return a promise instead, and then we can chain the promises. Assuming that Parse.User.logIn is a callback-style function (as is Parse.Query.find), you might do something like:
var Promise = require('bluebird');
var login = Promise.promisify(Parse.User.logIn);
var find = Promise.promisify(Parse.Query.find);
var outerOutput = [];
return login(yourArgsHere)
.then(function(user) {
return find(user.someValue);
})
.then(function(results) {
var innerOutput = [];
// do something with innerOutput or outerOutput and render it
});
This should look familiar to synchronous code that you might be used to, except instead of saving the returned value into a variable and then passing that variable to your next function call, you use "then" handlers to chain the promises together. You could either create the entire output variable inside of the second then handler, or you can declare the variable output prior to even starting this promise chain, and then it will be in scope for all of those functions. I have shown you both options above, but obviously you don't need to define both of those variables and assign them values. Just pick the option that suits your needs.
You can also use Bluebird's promisifyAll() function to wrap an entire library with equivalent promise-returning functions. They will all have the same name of the functions in the library suffixed with Async. So assuming the Parse library contains callback-style functions named someFunctionName() and someOtherFunc() you could do this:
var Parse = Promise.promisifyAll(require("Parse"));
var promiseyFunction = function() {
return Parse.someFunctionNameAsync()
.then(function(result) {
return Parse.someOtherFuncAsync(result.someProperty);
})
.then(function(otherFuncResult) {
var something;
// do stuff to assign a value to something
return something;
});
}
I have a few pointers. ... Btw tho, are you trying to use Parse's Promises?
You can get rid of those inner nested loops and a few other changes:
Use some syntax like this to be more elegant:
/// You could use a map function like this to get the files into an array of just thier names
var fileNames = matchedFiles.map(function _getJavaFile(item) {
return item && item.javaFile && item.javaFile.name // NOT NULL
&& item.javaFile.name.split('-')[0]; // RETURN first part of name
});
// Example to filter/retrieve only valid file objs (with dashes in name)
var matchedFiles = results.filter(function _hasJavaFile(item) {
return item && item.javaFile && item.javaFile.name // NOT NULL
&& item.javaFile.name.indexOf('-') > -1; // and has a dash
});
And here is an example on using Parse's native promises (add code above to line 4/5 below, note the 'then()' function, that's effectively now your 'callback' handler):
var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.select("score", "playerName");
query.find().then(function(results) {
// each of results will only have the selected fields available.
});

bluebird .all() does not call .then

I have an unknown number of async processes that might run from a request. There is a block of text to be modified by these processes.
UpdateScript is called with the text to be modified, it has a callback that I would like to run when everything is complete.
var promise = require('bluebird');
function updateScript(text, cb){
var funcChain = [],
re = some_Regular_Expression,
mods = {text: text};
while (m = re.exec(mods.text)) {
// The text is searched for keywords. If found a subprocess will fire
....
funcChain.push( changeTitleAsync(keyword, mods) );
}
promise.all(funcChain)
.then(function(){
// This is never called.
cb(mods.text);
});
}
function changeTitle(encryptedId, mods){
try{
// database request modifies mods.text
}catch(e){
throw e;
}
}
var changeTitleAsync = promise.promisify(changeTitle);
The changeTitle code is called but the "then" call is not
Partly the problem is incorrect use of promisify(). This is meant to convert a node-style function that takes a callback as it's last argument into one that returns a promise (see docs here).
Instead what you can do with your function above is have it return a new Promise manually like this:
function changeTitle(encryptedId, mods) {
return new Promise(function(resolve, reject){
try {
// do something then resolve promise with results
var result = ...
resolve(result)
} catch (e) {
// reject the promise with caught error
reject(e)
}
})
}
HOWEVER
There is one mistake above: I assume the db call to update the text is also asynchronous, sothe try /catch block will never catch anything because it will run through just as the db kicks off intially.
So what you would have to do is promisify the DB call itself. If you're using a node db library (like Mongoose, etc) you could run Promise.promisifyAll() against it, and use the Async versions of the functions (see promisifyAll section on above link for details).
Hope this helps!!

Manually promisifying pg.connect with Bluebird

I want to promisify node-postgres' pg.connect method along with the inner connection.query method provided in the callback.
I can .promisify the latter, but I need to implement the first one manually (if I'm missing something here, please explain).
The thing is, I'm not sure if this code is correct or should be improved? The code is working, I just want to know if I'm using Bluebird as meant.
// aliases
var asPromise = Promise.promisify;
// save reference to original method
var connect = pg.connect.bind(pg);
// promisify method
pg.connect = function (data) {
var deferred = Promise.defer();
connect(data, function promisify(err, connection, release) {
if (err) return deferred.reject(err);
// promisify query factory
connection.query = asPromise(connection.query, connection);
// resolve promised connection
deferred.resolve([connection,release]);
});
return deferred.promise;
};
Throw all that horrible callback code away, then do this somewhere in your application initialization:
var pg = require("pg");
var Promise = require("bluebird");
Object.keys(pg).forEach(function(key) {
var Class = pg[key];
if (typeof Class === "function") {
Promise.promisifyAll(Class.prototype);
Promise.promisifyAll(Class);
}
})
Promise.promisifyAll(pg);
Later in anywhere you can use the pg module as if it was designed to use promises to begin with:
// Later
// Don't even need to require bluebird here
var pg = require("pg");
// Note how it's the pg API but with *Async suffix
pg.connectAsync(...).spread(function(connection, release) {
return connection.queryAsync("...")
.then(function(result) {
console.log("rows", result.rows);
})
.finally(function() {
// Creating a superfluous anonymous function cos I am
// unsure of your JS skill level
release();
});
});
By now there are a number of libraries which do this for you:
pg-promise - generic Promises/A+ for PG
postgres-bluebird
dbh-ph
pg-bluebird
Update for bluebird 3:
The pg.connectAsync(...).spread(function(connection, release) { ... }) call will not work anymore, because the API of bluebird has changed: http://bluebirdjs.com/docs/new-in-bluebird-3.html#promisification-api-changes .
The problem is that promisifyAll in bluebird 3 does not handle multiple arguments by default. This results in the .spread() call reporting a TypeError like the following:
TypeError: expecting an array or an iterable object but got [object Null]
To solve this, you can explicitly enable multiple arguments for connect / connectAsync. Do the following after all the promisifying stuff mentioned above:
...
pg.connectAsync = Promise.promisify(pg.connect, { multiArgs: true });
I suggest to modify Petka Antonov solution a bit
var Promise = require('bluebird');
var pg = require('pg');
Object.keys(pg).forEach(function (key) {
var Cls = null;
try {
Cls = pg[key];
if (typeof Cls === 'function') {
Promise.promisifyAll(Cls.prototype);
Promise.promisifyAll(Cls);
}
} catch (e) {
console.log(e);
}
});
Promise.promisifyAll(pg);
here 'pg[key] wrapped up in try-catch block because pg[key] can retrun error when attempt to access pg['native']

How to get callback value in node.js in a variable

this is my code.
var fs = require('fs')
var test = readafile('file.txt', function(returnValue) {
console.log(returnValue);
test = returnValue;
});
console.log(test);
function readafile(filepath,callback){
var attachment_path = filepath;
fs.readFile(attachment_path, function(err,data){
var attachment_encoded = new Buffer(data, 'binary').toString('base64');
callback(attachment_encoded);
});
}
In that if i need that return value of that function in variable test means how to achieve that ?
In that console.log(test) it says undefined.
since it is a callback function.
How to get it properly ?
You can't really expect getting a synchronous behavior (like getting a return value) with asynchronous code. You can use fs.readFileSync to avoid the asynchronous aspect or just use your value inside your callback.
Otherwise the async module could help you out.

Resources