the following function creates new folder on my server via xmlrpc
var createFolder = function(folder_name) {
var defer = Q.defer();
client.methodCall('create_folder', [sessionID, folder_name], function(err, resp) {
if (err) {
if (err.responseString && err.responseString.match('already exist')) {
//call the same function recursively with folder_name+Math.round(Math.random()*100)
} else {
defer.reject(err);
}
} else {
defer.resolve(folder_name);
}
});
return defer.promise;
}
The functions creates a new folder successfully
However, if folder already exists i want to fire this function again recursively with new folder name and then return it in promise so that whenever this function is called it'll return the folder name doesn't matter how many times it was executed
something like
createFolder('directory').then(function(resp){
console.log(resp);// may return directory || directory1 .... etc
});
**EDIT **
so i manged to achieve this by passing the defer object
let me know if there are more elegant ways of achieving this
var createFolder = function(folder_name,defer) {
defer =defer || Q.defer();
client.methodCall('create_folder', [sessionID, folder_name], function(err, resp) {
if (err) {
if (err.responseString && err.responseString.match('already exist')) {
return createFolder(folder_name+Math.round(Math.random()*100,defer)
} else {
defer.reject(err);
}
} else {
defer.resolve(folder_name);
}
});
return defer.promise;
}
Never do any logic in plain (non-promise) callbacks. Promisify at the lowest level:
var defer = Q.defer();
client.methodCall('create_folder', [sessionID, folder_name], function(err, resp) {
if (err) defer.reject(err);
else defer.resolve(folder_name);
});
return defer.promise;
Or much simpler with Q.ninvoke:
return Q.ninvoke(client, 'methodCall', 'create_folder', [sessionID, folder_name]);
Now we can start implementing our recursion. It's quite simple with a then callback, from which you can return another promise. In your case:
function createFolder(folder_name) {
return Q.ninvoke(client, 'methodCall', 'create_folder', [sessionID, folder_name])
.catch(function(err) {
if (err.responseString && err.responseString.match('already exist')) {
return createFolder(folder_name+Math.floor(Math.random()*100));
} else {
throw err;
}
});
}
Here is a bad simple way of solving your problem:
var createFolder = function(folder_name) {
var defer = Q.defer();
client.methodCall('create_folder', [sessionID, folder_name], function(err, resp) {
if (err) {
if (err.responseString && err.responseString.match('already exist')) {
//call the same function recursively with folder_name+Math.round(Math.random()*100)
defer.resolve(createFolder(folder_name+Math.round(Math.random()*100)));
} else {
defer.reject(err);
}
} else {
defer.resolve(folder_name);
}
});
return defer.promise;
}
However, defer is considered bad practice. Here is a very nice article about promises.
You should favor something like:
var createFolder = function(folder_name) {
return Q.Promise(function(resolve, reject){
client.methodCall('create_folder', [sessionID, folder_name], function(err, resp) {
if (err) {
if (err.responseString && err.responseString.match('already exist')) {
//call the same function recursively with folder_name+Math.round(Math.random()*100)
resolve(createFolder(folder_name+Math.round(Math.random()*100)));
} else {
reject(err);
}
} else {
resolve(folder_name);
}
});
});
}
EDIT: as noted by #Bergi, this is still not right and hard to debug. Any potential errors thrown from the callback of methodCall won't actually reject the promise and will most likely be swallowed (even though this callback seems very little error-prone, it might evolve). Please refer to his answer for a better way of doing this.
Also, see the official Q doc here.
Related
I have written below code in one file:
models/exported.js
module.exports = {
processedList: function(store_name) {
var t;
var tradeIds = exported.find({storename: store_name}, function (err, value) {
if (err) return console.error(err);
return value;
}).select('tid -_id');
}, // Export connection here
};
I have another file in routes
routes/exported.js
var exported = require('../models/exported.js');
var tradeIds = exported.processedList(storename);
console.log('simer'+tradeIds);
}
but I get undefined in console.log. If instead of return statement in processedlist I write console.log then the result gets console. But my requirement is to return data from model file to route file.
I am new to express and node js.
I guidance would be highly appreciated.
Acoording to your question, you want calling a function from route and get return response from your function to route. simple use callback functions.
models/exported.js
module.exports = {
processedList: function (store_name, callback) {
var t;
var tradeIds = exported.find({storename: store_name}, function (err, value) {
if (err) {
callback("error", err)
} else {
callback("success", value)
}
}).select('tid -_id');
}
}
routes/exported.js
var exported = require('../models/exported.js');
exported.processedList('storename', function (err, results) {
if (err == 'error') {
console.log(err);
} else {
console.log(results);
}
});
You are trying sync operation in async environment. processedList may or may not have completed when you try to console log tradeIds. NodeJS would not wait for it to complete because it is asynchronous in nature (by design and it is not a bug). You can pass callback rather than executing this way.
models/exported.js
module.exports = {
processedList: function(store_name, cb) {
var t;
var tradeIds = exported.find({storename: store_name}, function (err, value) {
if (err) return cb(err);
cb(null, value);
}).select('tid -_id');
}, // Export connection here
};
routes/exported.js
var exported = require('../models/exported.js');
exported.processedList(storename, function(err, results) {
if (err) { console.log(err); }
console.log(results);
});
This makes sure that console.log happens only when processedList finishes execution.
I have a question about asynchronous function. Here my function "My_function":
function My_function (my_name, callback){
stmt = db.prepare ("SELECT number_table1 from my_table1 WHERE user=?");
stmt.bind(my_name);
stmt.get(function(error,row){
if(error){
throw err;
}
else{
if(row){
callback(number_table1);
}
else{
console.log("error");
}
}
});
}
Work fine but I have 2 tables and I need do other query and I need add two numbers so... in my function I need do too this query:
stmt = db.prepare ("SELECT number_table2 from my_table2 WHERE user=?");
and finally return back in my callback "number_table1 + number_table2".
Somebody know how to solve it? Thanks in advance.
Best regards!
In cases like your's I like to use the async module, because the code will be more legible. Example:
var async = require('async');
function My_function(my_name, callback) {
var stmt = db.prepare("SELECT number_table1 from my_table1 WHERE user=?");
stmt.bind(my_name);
stmt.get(function (error, row) {
if (error) {
callback(error, null);
} else {
if (row) {
callback(null, number_table1);
} else {
callback(new Error("row not found"), null);
}
}
});
}
//if you need the results in a specific order, you can use "series" instead of "parallel".
async.parallel(
//array of functions
[
function (callback) {
My_function('firstName', callback);
},
function (callback) {
My_function('secondName', callback);
}
],
//results when all functions ends
//the results array will equal [number_table1, number_table2], but the order can be different, because of the parallelism
function (err, results) {
if (err) {
//handle the err
} else {
//do something
}
}
);
Docs:
http://caolan.github.io/async/docs.html#parallel or
http://caolan.github.io/async/docs.html#series
You need to synchronize the functions so that you can be sure both their results are ready before calling back. You can do this using promises: https://www.promisejs.org/
Make two regular functions (no callbacks), one for each query (function1, function2)
Make both return a promise
Then you can do
function My_function(my_name) {
var value1;
function1(my_name)
.then(function(resultFromFunction1) {
value1 = resultFromFunction1;
return function2(my_name);
})
.then(function(resultFromFunction2) {
var result = value1 + resultFromFunction2;
return result;
});
}
}
Make sure to catch errors and handle different outcomes, what I presented is its simplest form.
Update
Here is an example of a function doing a query and returning a promise
function1 = function(user) {
return new Promise(function (resolve, reject) {
pool.getConnection(function (err, connection) {
if(err) {
reject ({status : false, message : "Error in connection database"});
} else {
connection.query('SELECT number_table1 from my_table1 WHERE user=?', [user], function(err, rows){
connection.release();
if(!err) {
resolve ({status: true, message: rows});
} else {
reject ({status: false, message: err});
}
});
}
});
});
}
Make the table names function parameters. Convert that function to use async/await or promise. Use Promise.all to run both queries.
I'm wondering what the best way to handle errors in long functions with promises are?
My function:
module.exports = function(data) {
var deferred = Q.defer();
var config = {};
fs.readdir(path, function(err, files) {
if (err) {
deferred.reject(new Error(err));
}
var infoPath = false;
files.forEach(function(filename) {
if (filename.indexOf('.info') !== -1) {
infoPath = path + '/' + filename;
config['moduleName'] = filename.replace('.info', '');
}
});
if (!infoPath) {
deferred.reject(new Error('Did not find .info-file'));
}
if (files.indexOf(config['moduleName'] + '.module') > -1) {
config.type = 'Modules';
}
else {
deferred.reject(new Error('Unknown project type'));
}
// Parse the info file.
fs.readFile(infoPath, function (err, content) {
if (err) {
deferred.reject(new Error(err));
}
data.config = config;
data.infoContent = content.toString();
deferred.resolve(data);
});
});
return deferred.promise;
};
As far as I understand it this is the way to use Q.defer. But if a error is thrown, I don't want/need it to try the rest of function. Am I missing something or are there a better way to do this?
Rejecting a promise doesn't miraculously stop the function from executing the rest of its code. So after rejecting, you should return from the function:
if (err) {
deferred.reject(new Error(err));
return;
}
Or shorter:
if (err) {
return deferred.reject(new Error(err));
}
I don't understand how to call a function recursively in node.js for example:
var releaseStock = function (callback) {
getItems(function (err, items) {
if (err) {
return callback(err);
} else {
if (items) {
return callback(items);
} else {
setTimeout(function() {
releaseStock(callback);
}, 5000);
}
}
});
};
How can i make it work?
I'm not entirely sure what you want to do, but I suspect it is something along the lines of:
var releaseStock = function(callback) {
// get items from somewhere:
var items = getItems();
if (!items) {
// if there are no items, try again (recurse!):
return releaseStock(callback);
}
// if there are items, give them to the callback function:
return callback(items);
};
I've read through a lot of different articles on promisejs but can't seem to get it to work for my code. I have async code that works and does what I need but it's very long and doesn't look as clean as it could with promise.
Here's the two links I've been really looking into: http://jabberwocky.eu/2013/02/15/promises-in-javascript-with-q/ and https://spring.io/understanding/javascript-promises.
mainCode.js
accountModel.findOne({username: body.username}, function(err, usernameFound) {
console.log("here");
if (err) {
console.log(err);
} else {
console.log("here1");
anotherClass.duplicateUsername(usernameFound, function(err, noerr) {
if (err) {
console.log("error");
res.status(409).send("username");
} else {
console.log("here2");
accountModel.findOne({email: body.email}, function(err, emailFound) {
if (err) {
console.log("error2");
} else {
console.log("here3");
console.log(emailFound);
}
});
}
});
}
});
// anotherclass.duplicateUsername
anotherClass.prototype.duplicateUsername = function(usernameFound, callback) {
if (usernameFound) {
callback(usernameFound);
} else {
callback();
}
}
current promise code (in mainCode.js):
var promise = userModel.findOne({
username: body.username
}).exec();
promise.then(function(usernameFound) {
console.log("usernameFound")
return userCheck.duplicateUsername(usernameFound);
}).then(function(usernameFound) {
console.log("NOERR:" + usernameFound + ":NOERR");
console.log("noerror");
return;
}, function(error) {
console.log(err);
console.log("error");
res.sendStatus(409);
return;
});
When I run my promise code, it goes to duplicateUsername, does callback() but then doesn't print anything in the promise code.
duplicationUsername needs to return a promise, otherwise the promise chaining will get the value returned from calling callback (which would be undefined).
Something like this should work:
anotherClass.prototype.duplicateUsername = function(usernameFound) {
var deferred = Q.defer();
if (usernameFound) {
deferred.resolve(usernameFound);
} else {
deferred.reject();
}
return deferred.promise;
}
So it seems like I needed to "promisify" my own functions before I could use them.
Here's how I did it with Q:
var Q = require('q');
anotherClass.prototype.duplicateUsername = function(username, callback) {
return new Promise(function(resolve, reject) {
var deferred = Q.defer();
if (usernameFound) {
deferred.reject("error);
} else {
deferred.resolve("no err: duplicate username");
}
deferred.promise.nodeify(callback);
return deferred.promise;
});
}
Here's how to do it with Bluebird:
userCheck.prototype.duplicateUsername = function(usernameFound) {
return new Promise(function(resolve, reject) {
if (usernameFound) {
reject("error");
} else {
resolve();
}
});
}
Then in my mainClass, I just used them by calling the methods and then .then(//blah)