This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I am trying to use async to collect some additional data to my array.
for this purpose ive created the following:
User_has_academy_module.findAll({
include: [{model: Module, include: [Category, ModuleType]}],
where: {academy_team_id: team_id, user_id: user_id}
}).then(function (modules) {
var i = 0;
async.map(modules, function (module,moduleCallback) {
var act = Academy_Attempt.build();
if(module.dataValues.is_complete == 1){
act.findByUserTeamAndModule(module.dataValues.user_id, module.dataValues.academy_team_id, module.dataValues.module_id, function (result) {
module.dataValues.academy_attempt = result;
moduleCallback(null, module);
}, function (error) {
})
}
});
onSuccess(modules);
})
as you can see from the above i first collect an array called modules that i need loop over for each of these modules i want to find additonal data if a value called is_complete == 1
once it finds a value it should set the module.dataValues.academy_attempt = result
Once all of the modules have been iterated it should call the callback (onSuccess) and return the modules.
However it runs onSuccess before the async call.
So my question is what am i doing wrong and how can fix it?
You need to run onSuccess in a completion callback to async.map. The first callback is the iterator, runs for every mapped element; the second callback (which you currently aren't using) runs after all iterations have completed.
async.map(modules, function (module,moduleCallback) {
//...
}, function(err, modules) {
onSuccess(modules);
});
Currently, your code queues up the asynchronous map job and then runs onSuccess without waiting for map to finish (or even start).
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed last year.
Whenever I try to get data from chrome.storage, it returns undefined.
chrome.storage.sync.get('courses', function(result) {
currentCourses = result.courses
console.log(currentCourses)
currentCourses.push(coursename)
chrome.storage.sync.set({courses: currentCourses}, function() {
alert(`Course "${coursename}" has been added !`)
});
}
userCourses = async () => {
await chrome.storage.sync.get('courses', function(result) {
return(result.courses)
});
}
courseData = userCourses()
console.log(courseData)
I found an answer here on stack overflow, but it is giving the same error. I am new to JS, and not comfortable with Promises.
I tried the example from the official docs, but it is also giving the same error as below.
Can someone help me with a solution, or modify my code ?
Wrap the call to storage in a promise and await it:
function getStorageValuePromise(key) {
return new Promise((resolve) => {
chrome.storage.sync.get(key, resolve);
});
}
await getStorageValuePromise('val');
You use chrome.storage.sync.get() with a completion callback. But notice that the data you retrieve using that .get() method isn't available except within the callback.
chrome.storage.sync.get(['key'], function(result) {
console.log('Value currently is ' + result.key);
});
is the example from the docs. It is the invocation of a function. But that function always and necessarily returns undefined.
Notice that the first parameter to .get() is an array of keys. Your code lacks the array.
The second parameter is the callback function. It looks like this:
function (result) {
}
Within the function result.key is the key you requested, and result.value is whatever you stored in the key. You're looking at result.courses, which isn't defined.
Control flow.
The call to .get() completes immediately, always.
At some later time the callback is called.
This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
Closed 2 years ago.
Supposing that I have a Post schema, I want a method with this structure here:
function getPostDetails(post_id)
{
// The function searches the db for a document with that id,
// Finds it, and returns an object containing some of its details:
return {
title: post.title,
thumbnail: post.thumbnail,
views: post.views
// ....
};
}
It must have this form, I have a lot of async, lambda, and nested functions and I don't want to make that code messier...
I did a lot of research but didn't find the way of doing it, maybe because I suck at handling promises and async code? yes!
Mongoose calls are done asynchronously. They cannot be made synchronously and it is also bad idea to make DB calls synchronous.
You have 2 options, either you make function asynchronous to return promise or add a callback parameter.
Using async await.
async function getPostDetails(post_id) {
const post = await queryDb(post_id)
const data = map(post) // convert generic post to desire schema
return data
}
Using promises without async / await.
function getPostDetails(post_id) {
return queryDb(post_id).then(post => map(post))
}
Using callback.
function getPostDetails(post_id, callback) {
queryDb(post_id).then(post => map(post)).then(post => callback(post))
}
This question already has answers here:
How to use fetch within a for-loop, wait for results and then console.log it
(5 answers)
Closed 2 years ago.
I go through all the elements of the array and form a request for each, how can I display a success message only after all requests have been completed?
saveAllPages() {
const allStagesData = JSON.parse(JSON.stringify(this.data.pages)).map(el => {
const id = el.id
apiService.postCurrentScript(el, id)
??? alert('success')
}
Maybe I should use Promise all, but how implement it here?
I would suggest using async-await as it makes code cleaner. Async-await is just an alternaitive to using promises and is many times considered a better choice. I have converted your function into arrow function. The implementation is given below:
saveAllPages = async () => {
const allStagesData = await (function which returns promise);
if(allStagesData){
alert("success");
}
}
saveAllPages();
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
Using NodeJS, I'm trying to get info from the database on a list of IDs and populate an array of objects. I need this to process synchronously. I'm having trouble figuring out how to do this so the next function call will wait for the previous one to finish before being called. Then all of the 'each' iterations to finish for the return to be called.
Example:
getInfo();
function getInfo(){
var return_arr = Array();
var ids = getListOfIDs();
// loop through each id getting more info from db
$.each( ids, function( i, v ){
return_arr.push(getFullInfo( id ));
});
return return_arr;
}
function getListOfIDs(){
// database call to get IDs
// returns array
}
function getFullInfo(){
// database call to get full info
// returns object
}
This is a simplified example, so assume that a single query to get all info will not work as there are multiple joins going on and post processing that needs to take place in js. Also, assume I'm doing proper error handling, which I omitted in my example.
Your database queries are asynchronous so you need to either use callbacks or promises to perform your work once the database returns with results.
function getListOfIDs(callback) {
// database call to get IDs
db.query('...', function(data) {
// call the callback and pass it the array
callback(data);
});
}
function getInfo() {
// pass an anonymous function as a callback
getListofIDs(function(data) {
// we now have access to the data passed into the callback
console.log(data);
});
}
Your current code example is synchronous, although I don't know how your db code works. The each loop is synchronous it just iterates over your ids and calls the getFullInfo function.
I'm not sure why you want synchronous code though as it doesn't utilise Nodes event loop architecture.
What I would do is use a good Promises framework such as Bluebird (http://bluebirdjs.com/docs/api/promise.each.html) with Promise.each ensuring each iteration occurs serially. Or you could also use a Callback library such as async (http://caolan.github.io/async/) with async.eachSeries. Either of these will ensure that you (a) get the benefit of asynchronous and (b) iterate in a serial fashion.
Promise way to do it:
function getListOfIDs() {
return new Promise((resolve, reject) => {
// database call
if (err)
{
reject(your_db_err);
return;
}
resolve(your_db_result);
});
}
function getInfo() {
getListOfIDs().then((result) => {
//do whatever you want with result
})
.catch((err) => {
//handle your err
});
}
This question already has answers here:
Hidden threads in Javascript/Node that never execute user code: is it possible, and if so could it lead to an arcane possibility for a race condition?
(3 answers)
Closed 7 years ago.
In many js examples, I see calls to functions doing tasks asynchronous, for example:
var objectStoreTitleRequest = objectStore.get(title);
objectStoreTitleRequest.onsuccess = function() {
// Grab the data object returned as the result
var data = objectStoreTitleRequest.result;
}
(This example is based on https://developer.mozilla.org/en-US/docs/Web/API/IDBRequest/onsuccess)
I wonder how this could work if the async execution finished before the onsuccess handler is set. I expected that event handlers added before execution of the async function, but all js examples add handlers after the call (in this case: get()). How is this internally solved? And how can I implement a custom object which provides a similar API? I think this must be something like
{self.result = do_work(); wait for onsuccess handler is set...; if handler_avail -> self.onsuccess(); }
Because Javascript is strictly single-threaded, asynchronous operations can only run their callbacks once other code has finished running.
Therefore, it is impossible for the request to finish between two lines.
This is exactly the reason why you should never call a callback function / event handler synchronously.
For example, the following code is wrong:
function async(val, cb) {
if(val < 0) {
cb();
}
else {
setTimeout(cb, val);
}
}
And must instead be implemented similar to:
function async(val, cb) {
if(val < 0) {
setTimeout(cb, 0);
}
else {
setTimeout(cb, val);
}
}