This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
What I want to do:
var found = false;
while (!found){
var result = db.getNextRecord();
if (result == search_term){
return result;
}
}
The problem is, getNextRecord is asynchronous
var nothing_returned = db.getNextRecord(function(err, result){
// I have the result in this callback, but not before
});
Given the behavior of getNextRecord(cb), how can I rewrite the above code snippet to get the same outcome?
Since you have a function that's async and you want to call in synchronously, you have two choice. Use a sync version of the method if there is one available, but if not, then you'll have to change your logic.
The following snippet should do what you want, it does require the async library.
var async = require('async');
var result;
async.whilst(
function () {
return !result;
},
function (callback) {
db.getNextRecord(function (err, record) {
if (err)
{
return callback(err);
}
if (result == search_term)
{
result = record;
}
return callback();
});
},
function (err) {
// Search is complete, do what you wish with result in this function. This function
// will be called when whilst is done or if getNextRecord got an error.
}
);
I'm sure there's a shorter way to do this if you want to change the logic even more, but this is similar to doing a while but asynchronously.
Use the async library. Its until function looks like what you need: https://www.npmjs.com/package/async#until
var async = require('async');
var latestResult = null;
async.until(function () {
return latestResult == search_term;
}, function () {
db.getNextRecord(function (err, result) {
latestResult = result;
});
}, function () {
// now you can do something with latestResult
});
You should also consider whether it makes sense to do this in your app or have the database query include this filtering.
With babel and new JS:
import {promisify as pr} from 'es6-promisify';
async function find(search_term) {
let found = false, result=null;
while (!found){
let result = await pr(db.getNextRecord)();
if (result == search_term){
found=true;
}
}
return result;
}
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I really need help with that I spent a lot of time trying to understand that but I don't get it.
I'm using nodeJS and MongoDB
I want to do a function that returns true or false depending on if the email is in the database:
I have done that
function isUserRegistered(email) {
MongoClient.connect(url, function (err, db) {
if (err) throw err;
let database = db.db(dataBaseName);
let query = { "email": email };
var userCollection = database.collection(collectionName)
userCollection.find(query).toArray(function (err, result) {
if (err) throw err;
db.close();
if (result.length > 0) {
return true;
} else {
return false;
}
});
});
}
console.log(isUserRegistered("jack#gmail.com").toString());
But when I test it doesn't work because isUserRegistered() is undefined at the time I try to print it.
I have tried to do callback functions, and I achieved to print either "false" or "true" with that, but with a callback function, I'm only starting a new function and the isUserRegister() doesn't return a boolean, so I can't do something like that later on my program:
if (isUserRegister(email){
// Try to login
} else {
// try to create the account
}
I have also look for async and await, but I don't know where I should use it.
Can it be fixed in a simple way?
Thank you
The problem is that you can't directly return a value from a callback (see this for more information).
Since the NodeJS MongoClient supports promises out of the box, you can rewrite and simplify your code with async/await very easily. Note that this still needs error handling, but it should give you a start:
async function isUserRegistered(email) {
const client = await MongoClient.connect(url);
const db = client.db(dataBaseName);
const query = {
"email": email
};
const result = await db.collection(collectionName).find(query).toArray();
if (result.length > 0) {
return true;
} else {
return false;
}
}
(async () => {
console.log(await isUserRegistered("jack#gmail.com"));
})();
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
var async = require('async');
var square = function (id, callback) {
Business.prototype.getBusinessUser(id,function(userObject){
return callback(userObject);
});
};
async.eachSeries(findBusinessResult, function (businessObject, callback) {
//console.log("results from square");
var result = square(businessObject["id"] , function(result){
console.log(result);
});
callback(); // Alternatively: callback(new Error());
}, function (err,results) {
if (err) { throw err; }
console.log('Well done :-)!');
console.log(results);
});
Why does the result always become undefined: any help please.
async is reserved word in ES7 and might give you problem later, when it's implemented.
What you might want to consider is actually using async/await togheter with babel.
Some browser is starting to implement it already
var square = id =>
new Promise(rs =>
Business.prototype.getBusinessUser(id, rs)
)
async search() {
for (let businessObject of findBusinessResult) {
let result = await square(businessObject.id)
console.log(result)
}
}
I hope this will be a game changer solution for most ppl. This is making ASYC java callback into somthing which look like sync with effiecent callback handling. Its my three days of challange. [Callbacks][1] are indeed a a major challage in javacript and here is how to solve issue using promises .
install bluebird
npm install bluebird --save
//inyour code
var Promise = require('bluebird'); //yeah awsome bird indeed :)
function extendBusinessObjectPromise(id,element) {
return new Promise(function(resolve, reject) {
Business.prototype.getBusinessUser( id ,function(userObject){
var extend = require('util')._extend;
mergedJson = userObject;
elements = element;
extend({},elements);
extend(elements,mergedJson);
global.businesssWithUsers.push(elements); //sahred object
resolve(global.businesssWithUsers)
})
})
}
//NOW how do you i call the promise result inside a foreach loop and get its value returned as callback result. seem crazy idea :(
Person.prototype.getPersons = function(filter , callback) {
//this my own Bill count since i have one using one user account
global.businesssWithUsers = [];
models.PersonModel.findAll(filter_combined).then(function (findBusinessResult) {
global.businesssWithUsers = []
var extend = require('util')._extend;
var mergedJsonArray = [];
if (findBusinessResult==null) {
return callback(false,"no result found");
}
var promiseBusinessResult = null; //promise reslover :)
var findBusinessResult =JSON.parse(JSON.stringify(findBusinessResult));
findBusinessResult.forEach(function(eachElement) {
var id = element["userId"];
promiseBusinessResult = extendBusinessObjectPromise(id,element);
});
promiseBusinessResult.done(function(result){
callback(true,result); //pass the result to main function
});
}).catch(function (err) {
log.error(err["errors"][0]["message"])
callback(false,err["errors"][0]["message"])
return
})
}
Success at last. Cheers!
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I was having an obsolete JS library which was making API call Synchronous for which I decided to write JS function which can make them Async using jQuery.
In the following code the getData function is to be a generic function which makes API calls according to params passed and then extract data from the received XML/JS.
The second call(getAllData2) needs values from the result set of getData so I need a callback kind of thing in which the subsequent call can be made after the data is available from the 1st call.
Can this be achieved without the ajax success call back as I want getData function to remain generic.
I had tried jQuery promises but that gives me the raw data of the call instead of the processed one which I will have to process in each of the done callback separtely.
getData(param1,param2..){
var retData = {};
......Param dependent code here..
jQuery.ajax({
url:....,
.......
success: function(resp){
if(resp.length > 0){
jQuery.each(resp,function(key,val){
var i = 0;
var retObj = {};
jQuery.each(val,function(k,v){
retObj[k] = v;
i++;
});
retData[key] = retObj;
});
}
---Process recieved XML/JS and Insert values in retData here--
}
});
return retData;
}
var getAllData = getData(x,y);
var getAllData2 = getData(a,b); // this call needs param from getAllData.
Please suggest.
Thanks
Promises are indeed what you should be using.
That will allow you to structure your logic like this:
function processResult(resp) {
var retData = {};
if(resp.length > 0){
jQuery.each(resp,function(key,val){
var retObj = {};
jQuery.each(val,function(k,v){
retObj[k] = v;
});
retData[key] = retObj;
});
}
return retData;
}
getData(x, y)
.then(function (result) {
var processed = processResult(result);
return getData(processed);
})
.then(function (result) { // result is the result of the second getData()
// use result
});
If you want to do pre-processing of the results in your getData() function, again you can do this with promises:
function getData(param1,param2..) {
......Param dependent code here..
return $.ajax({
url:....,
.......
})
.then(function (resp) {
var retData = {};
if(resp.length > 0){
$.each(resp,function(key,val){
var retObj = {};
$.each(val,function(k,v){
retObj[k] = v;
});
retData[key] = retObj;
});
}
return retData;
});
}
getData(x, y)
.then(function (processedResult) {
return getData(processedResult, otherParameter);
})
.then(function (processedResult2) {
// use processedResult2
});
I got a question regarding the solr-client module of nodejs. I'm using this module for querying against a solr-index.
The module itself works fine as long as I don't have to wait for finishing of the query and as long I need the result only as a async result.
But currently I cannot find out, how I will be able to await the finishing of a search request and use the result in a sequential way.
I have the follwing method in my manager
SolrManager.prototype.promisedQuery = function(query, callback) {
var solrClient = solr.createClient(this.configuration.cores.page);
var docs = null;
var finished = false;
var deferred = Q.defer();
var request = solrClient.search(query, function(err,obj){
if (!err) {
if (obj.response.numFound > 0) {
deferred.resolve(obj.response.docs);
} else {
deferred.resolve(null);
}
} else {
deferred.reject(err);
}
});
var records = null;
var promise = deferred.promise;
promise.then(function(result) {
records = result;
}).fail(function(error){
records = error;
});
return records;
};
The problem here is, that I try to wait for the result of the query and use it as return value of "promisedQuery".
I try since days to use this method in a sequential call, also with different additional modules like "wait.for", "q", etc. but nothing seems to work.
The callback function of the solr-client will always be executed after the manager-method has already returned. Also the promise-methods will be even called after the return from the manager-method.
Can someone help me out on that topic or have some tips, how I can await the response of the solr-client-search operation and then give it back in a sequential way?
Thanks for any help.
Udo Gerhards
over one week, it seems now that I have found a solution:
SolrManager.prototype.promisedQuery = function(query, callback) {
var solrClient = solr.createClient(this.configuration.cores.page);
var docs = null;
var deferred = Q.defer();
var request = solrClient.search(query, function(err,obj){
if (!err) {
if (obj.response.numFound > 0) {
deferred.resolve(obj.response.docs);
} else {
deferred.resolve(null);
}
} else {
deferred.reject(err);
}
});
return deferred.promise;
};
in all other managers, which are calling the above function:
...
var dbPromise = this.solrManager.promisedQuery(query);
var _self = this;
return Q.async(function*(){
var result = yield dbPromise;
return result;
});
...
After first tests, it seems that synchronized methods will wait until the promise is settled.
The only thing is, that it runs only with NodeJs version 0.11.10, which supports generator functions, with activated --harmony-flag and "q"-module.
Best regards
Udo
You are just using the promises a bit incorrectly. Instead of returning records, you need to return 'deferred.promise'. It should look something like this (note that you don't need the callback you passed into promisedQuery).
SolrManager.prototype.promisedQuery = function(query) {
var solrClient = solr.createClient(this.configuration.cores.page),
deferred = Q.defer();
solrClient.search(query, function(err,obj){
if (!err) {
if (obj.response.numFound > 0) {
deferred.resolve(obj.response.docs);
} else {
deferred.resolve(null);
}
} else {
deferred.reject(err);
}
});
return deferred.promise;
};
To use it you would do something like:
SolrManager.promisedQuery(myquery)
.then(function (data) {
// data is whatever your 'resolved' in promisedQuery
}, function (err) {
// err is whatever you rejected in promisedQuery
});
based on rquinns answer I've changed the code like follows:
SolrManager.prototype.promisedQuery = function(query, callback) {
var solrClient = solr.createClient(this.configuration.cores.page);
var docs = null;
var finished = false;
var deferred = Q.defer();
var request = solrClient.search(query, function(err,obj){
if (!err) {
if (obj.response.numFound > 0) {
deferred.resolve(obj.response.docs);
} else {
deferred.resolve(null);
}
} else {
deferred.reject(err);
}
});
return deferred.promise;
};
...
DemoObject.prototype.toString = function() {
return SolrManager.promisedQuery(this.query).then(function(result){
return result['title'];
}).fail(function(error){
return error;
});
};
DemoObject.prototype.typeOf = function() {
return SolrManager.promisedQuery(this.query).then(function(result){
return result['title'];
}).fail(function(error){
return error;
});
};
I think, this is the right way to use the "promise"-object. But what happens when i do the follwing:
...
var demoObject = new DemoObject();
demoObject.query = "id:1";
console.log(''+demoObject);
...
or if I use "demoObject" by concatenating it to a string
...
var string = "Some string "+demoObject;
...
In case of the string concatenation, I'm currently not sure that the string will contain also the title field from the database. Same for console output.
Will nodejs be so intelligent that it resolves for e.g. the string concatenation "after" the results from the database will be available?
BR
Udo
I want to call a function after an asynchronous for loop iterating through values of an Javascript object finishes executing. I have the following code
for (course in courses) {
var url = '...' + courses[course];
request(url, (function (course) {
return function (err, resp, body) {
$ = cheerio.load(body);
//Some code for which I use object values
};
})(course));
}
This can be done in vanilla JS, but I recommend the async module, which is the most popular library for handling async code in Node.js. For example, with async.each:
var async = require('async');
var courseIds = Object.keys(courses);
// Function for handling each course.
function perCourse(courseId, callback) {
var course = courses[courseId];
// do something with each course.
callback();
}
async.each(courseIds, perCourse, function (err) {
// Executed after each course has been processed.
});
If you want to use a result from each iteration, then async.map is similar, but passes an array of results to the second argument of the callback.
If you prefer vanilla JS, then this will work in place of async.each:
function each(list, func, callback) {
// Avoid emptying the original list.
var listCopy = list.slice(0);
// Consumes the list an element at a time from the left.
// If you are concerned with overhead in using the shift
// you can accomplish the same with an iterator.
function doOne(err) {
if (err) {
return callback(err);
}
if (listCopy.length === 0) {
return callback();
}
var thisElem = listCopy.shift();
func(thisElem, doOne);
}
doOne();
}
(taken from a gist I wrote a while back)
I strongly suggest that you use the async library however. Async is fiddly to write, and functions like async.auto are brilliant.
A possible simple JS solution would be to do something like this.
var courses = {
lorum: 'fee',
ipsum: 'fy',
selum: 'foe'
};
var keys = Object.keys(courses);
var waiting = keys.length;
function completedAll() {
console.log('completed all');
}
function callOnCourseComplete(course, func) {
console.log('completed', course);
waiting -= 1;
if (!waiting) {
func();
}
}
var delay = 10000;
keys.forEach(function(course) {
var url = '...' + courses[course];
console.log('request', url);
setTimeout((function(closureCourse) {
return function( /* err, resp, body */ ) {
// Some code for which I use object values
callOnCourseComplete(closureCourse, completedAll);
};
}(course)), (delay /= 2));
});
Update: Probably a better Javascript solution would be to use Promises
const courses = {
lorum: 'fee',
ipsum: 'fy',
selum: 'foe',
};
function completedAll() {
console.log('completed all');
}
function callOnCourseComplete(courseName) {
console.log('completed', courseName);
}
let delay = 10000;
const arrayOfPromises = Object.keys(courses).map(courseName => (
new Promise((resolve, reject) => {
const url = `...${courses[courseName]}`;
console.log('request', url);
setTimeout((err, resp, body) => {
if (err) {
reject(err);
}
// Some code for which I use object values
resolve(courseName);
}, (delay /= 2));
}))
.then(callOnCourseComplete));
Promise.all(arrayOfPromises)
.then(completedAll)
.catch(console.error);