This question already has an answer here:
How to wait for forEach to complete with asynchronous callbacks?
(1 answer)
Closed 1 year ago.
Here is my code
Future<List<Record>> getRecordElements() async {
int i=0;
String at;
var cont =0;
List<String> name= [];
var db = await FirebaseDatabase.instance.reference().child("Volunteers/"+widget.vname+"/Records");
db.once().then((DataSnapshot snapshot){
Map<dynamic, dynamic> values = snapshot.value;
print(values);
values.forEach((key,values) async {
if(values["cont"]!=null){
//Few complicated operations
values.forEach((key,values) {
print(values);
if(key=="name"){
name.add(values);
}
});
});
});
print("name " + name.toString());
//few more operations
return items;
}
I have modified out irrelevent parts of the code.
Thing is, name is an array whose values are fetched from the database. Only after the array is set, can function proceed.
But what is happening is that name is being printed before it has been set. And hence the other operations after that are also being affected.
I need the fetching to finish first, and only then move ahead.
Please help
I think You Should fetch Your data at initializing stage i.e. you should create a function to fetch data from database and then call that function from initState
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I am writing a steam bot and am trying to check, if one of the items in a trade is worth below 1 USD. I need to access the "pass" variable, but it never works. Can someone help?
var receive = offer.itemsToReceive;
var pass = true;
receive.forEach(function(id) {
var args = id.split(",");
market.getItemPrice("some app id", some item name).then(function(result) {
var json = JSON.parse(JSON.stringify(result)); // returns e.G $0.08
var price = parseFloat(json.median_price.substring(1));
if(price*100 < 100) {
pass = false;
}
});
});
This question is asked a lot, but hopefully explaining it in your own problem's terms will help you understand.
Your code should wait for any possibility of pass = false;, but it doesn't because you call a asynchronous function --- imagine the code immediately moves on after calling that. Your foreach function is immediately processed and the next line is called until .getItemPrice responds some time later.
So instead, to "wait" for all the results, you can do something like:
var receive = offer.itemsToReceive;
var pass = true;
var itemReceivePromises = receive.map(id=>{
var args = id.split(",");
return market.getItemPrice("some app id", some item name).then(function(result) {
var json = JSON.parse(JSON.stringify(result)); // returns e.G $0.08
var price = parseFloat(json.median_price.substring(1));
if(price*100 < 100) {
pass = false;
}
});
});
Promise.all(itemRecievePromises).then(results=>{
console.log('pass',pass);
});
However, you should pass the "pass" result back through the promise instead of using a higher scoped variable.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
var historyQuesn = [];
db.collection('history_QUESTIONS').find({}).toArray().then((docs)=>{
var historyquesn = JSON.stringify(docs,undefined,2);
var historyquesn_parse = JSON.parse(historyquesn);
historyQuesn = historyQuesn.concat(historyquesn_parse);
},(err)=>{
console.log(err);
});
I want to make use of the array returned by the above query in another functions. I want to make use of the documents returned by the db.find() method in some another functions using nodejs! Basically i want to use the vlaue of 'historyQuesn' in another functions. Please Help!
Since the result of Your query will arrive to historyQuesn array when it's finished, so probably you call operation on data before the database query has finished. In Node.js all I/O operations are performed asynchronously thus Node goes further and execute Your code while it waits for the result of that query.
Possible solution is to pass a callback function that gets executed after the database query has finished. Quick example:
function queryCollection(collection, callback) {
collection.find({}).toArray(function(err, result) {
if (err) {
console.log(err);
} else if (result.length > 0) {
callback(result);
}
});
}
queryCollection(collection, function(result){
console.log(result);
// Proceed with Your result here
});
I recommend to read about asynchronous programming if You would like to use Node.js
I've drawn a simple flow chart, which basically crawls some data from internet and loads them into the database. So far, I had thought I was peaceful with promises, however now I have an issue that I'm working for at least three days without a simple step.
Here is the flow chart:
Consider there is a static string array like so: const courseCodes = ["ATA, "AKM", "BLG",... ].
I have a fetch function, it basically does a HTTP request followed by parsing. Afterwards it returns some object array.
fetch works perfectly with invoking its callback with that expected object array, it even worked with Promises, which was way greater and tidy.
fetch function should be invoked with every element in the courseCodes array as its parameter. This task should be performed in parallel execution, since those seperate fetch functions do not affect each other.
As a result, there should be a results array in callback (or Promises resolve parameter), which includes array of array of objects. With those results, I should invoke my loadCourse with those objects in the results array as its parameter. Those tasks should be performed in serial execution, because it basically queries database if similar object exists, adds it if it's not.
How can perform this kind of tasks in node.js? I could not maintain the asynchronous flow in such a scenario like this. I've failed with caolan/async library and bluebird & q promise libraries.
Try something like this, if you are able to understand this:
const courseCodes = ["ATA, "AKM", "BLG",... ]
//stores the tasks to be performed.
var parallelTasks = [];
var serialTasks = [];
//keeps track of courses fetched & results.
var courseFetchCount = 0;
var results = {};
//your fetch function.
fetch(course_code){
//your code to fetch & parse.
//store result for each course in results object
results[course_code] = 'whatever result comes from your fetch & parse code...';
}
//your load function.
function loadCourse(results) {
for(var index in results) {
var result = results[index]; //result for single course;
var task = (
function(result) {
return function() {
saveToDB(result);
}
}
)(result);
serialTasks.push(task);
}
//execute serial tasks for saving results to database or whatever.
var firstSerialTask = serialTasks.shift();
nextInSerial(null, firstSerialTask);
}
//pseudo function to save a result to database.
function saveToDB(result) {
//your code to store in db here.
}
//checks if fetch() is complete for all course codes in your array
//and then starts the serial tasks for saving results to database.
function CheckIfAllCoursesFetched() {
courseFetchCount++;
if(courseFetchCount == courseCodes.length) {
//now process courses serially
loadCourse(results);
}
}
//helper function that executes tasks in serial fashion.
function nextInSerial(err, result) {
if(err) throw Error(err.message);
var nextSerialTask = serialTasks.shift();
nextSerialTask(result);
}
//start executing parallel tasks for fetching.
for(var index in courseCode) {
var course_code = courseCode[index];
var task = (
function(course_code) {
return function() {
fetch(course_code);
CheckIfAllCoursesFetched();
}
}
)(course_code);
parallelTasks.push(task);
for(var task_index in parallelTasks) {
parallelTasks[task_index]();
}
}
Or you may refer to nimble npm module.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I need to mention that I'm new to Node.js in general but I'm not sure why for the following code will give me different outputs in console for questions and allQuestions variable ?
var models = require('./models')(mongoose);
var query = models.Question.find({});
var questions = Array();
query.exec(function(err, allQuestions){
//catch the error;
questions = allQuestions;
console.log(allQuestions);
});
console.log(questions);
Output of questions variable will be only: Mongoose: questions.find({}) { fields: undefined } while allQuestions will contain all the questions from database.
I need to know why ?
Also I need that my question variable contains allQuestions from database.
Thats because query.exec() runs the function you passed as parameter asynchronously and the last line console.log(questions); will be executed before the callback is.
If you need the value of questions, then use another callback:
var models = require('./models')(mongoose);
var query = models.Question.find({});
var questions = Array();
query.exec(function(err, allQuestions){
//catch the error;
questions = allQuestions;
console.log(allQuestions);
done();
});
function done() {
console.log(questions);
// handle `questions` here ...
}
I am creating an array of JSON objects which is then stored in mongodb.
Each JSON object contains a number of fields - each being populated before I save the object to mongodb.
Some of the Objects attributes are populated by making API calls to other websites such as last.fm but the returned value is not quick enough to populate the attribute before the object is saved to mongodb.
How can I wait for all attributes of an object to be populated before saving it? I did try async.waterfall but it still falls through without waiting and I end up with a database filled with documents with empty fields..
Any help would be greatly appreciated.
Thanks :)
You have a few options for controlling asynchrony in JavaScript:
Callback pattern: (http://npmjs.org/async) async.all([...], function (err) {
Promises: (http://npmjs.org/q) Q.all([...]).then(function () {
Streams: (http://npmjs.org/concat-stream) see also https://github.com/substack/stream-handbook
Since you say you are making multiple API calls to other websites, you may want to try:
async.each(api_requests,
function(api_request, cb) {
request(api_request, function (error, response, body) {
/* code */
/* add to model for Mongo */
cb();
});
},
function(err) {
// continue execution after all cbs are received
/* code */
/* save to Mongo, etc.. */
}
);
The above example is most applicable when you are making numerous requests following the same format. Please review the documentation for Waterfall (https://github.com/caolan/async#waterfall) if the input into your next step depends on the output of the previous step or Parallel (https://github.com/caolan/async#parallel) if you have a bunch of unrelated tasks that don't rely on each other. The great thing about async is that you can nest and string all the functions together to support what you're trying to do.
You'll either want to use promises or some sort of callback mechanism. Here's an example of the promise method with jPromise:
var jPromise = require('jPromise');
var promises = [];
for(var i = 0; i < 10; i++) {
promises.push(someAsyncApiCall(i));
}
jPromise.when(promises).then(function() {
saveThingsToTheDb();
});
Similarly, without the promise library:
var finished = 0;
var toDo = 10;
function allDone() {
saveThingsToTheDb();
}
for(var i = 0; i < toDo.length; i++) {
someAsyncApiCall(function() {
finished++;
if(finished === toDo) {
allDone();
}
});
}
Personally, I prefer the promise method, but that will only that well if the API you're calling returns some sort of a promise. If it doesn't, you'll be SOL and wrap the callback API with promises somehow (Q does this pretty well).