I am trying to execute the following code, however "// go do something else" keeps happening before "// do stuff with things"
It appears that my code is not waiting for mongoose.model('things').find() to finish before moving on. I've tried different variations of async/await and nothing seems to work.
Not getting errors an everything executes, just out of order.
const asyncFunction = async () => {
mongoose.connect(`mongodb+srv://...`);
mongoose.model('things', {data:String});
mongoose.model('things').find((err, things)=>{
// do stuff with things
}
console.log('something');
}
const otherAsyncFunction = async () {
await asyncFunction();
// go do something else
}
otherAsyncFunction();
Your asyncFunction doesn't return anything, so there's no point awaiting it.
You have no Mongoose schema.
The syntax to create a Mongoose model (doc) is :
const thingsShema = new mongoose.Schema({ data: 'string' });
const Thing = mongoose.model('thing', thingsShema );
You are creating your model, but then your model isn't stored in a variable and you're not using it at all.
mongoose.model('things') : this line creates a new Mongoose model but you're not passing it any schema. Anyway you already did that on the previous line.
.find() is asynchronous, and you're not returning its value.
You aren't passing any argument to .find(), only a callback function.
This code should work better :
const asyncFunction = async () => {
await mongoose.connect(`mongodb+srv://...`);
const thingsSchema = new mongoose.Schema({ data: 'string' });
const Things = mongoose.model('things', thingsSchema);
const foundThings = await Things
.find({}) // Query conditions (here, querying for 'everything', an empty object)
.lean() // Returns simple JSON and not a collection of Mongoose objects
.exec(); // returns a true Promise and not just a thenable
console.log('foundThings = ', foundThings);
return foundThings; // this returns a Promise, because 'async' functions always do
}
const otherAsyncFunction = async () => {
const result = await asyncFunction();
console.log("Result = ", result); // Normally this will log the same thing as 'foundThings'
// go do something else
}
otherAsyncFunction();
async functions return Promise object. When you exec await asyncFunction(), 'await' wait status asyncFunction() - resolve or reject.But in your code there are no resolve() or reject() functions. So you need to do like this:
const asyncFunction = async (resolve) => {
mongoose.connect(`mongodb+srv://...`);
mongoose.model('things', {data:String});
mongoose.model('things').find((err, things)=>{
// do stuff with things
});
console.log('something');
resolve()
}
const otherAsyncFunction = async () => {
await asyncFunction();
// go do something else
}
otherAsyncFunction();
Related
I'm newer to JavaScript and struggling to understand why this function just returns right away, even though I added an await. The code below is the minimal example to replicate what I am attempting to do. When I call add_user() from add(), id is undefined because add_user() is returning right away instead of waiting for completion of the query. I added the console log to verify that row.id is the value I expected (i.e. 1).
'use strict';
import sqlite3 from 'sqlite3'
import { open } from 'sqlite';
async function add_user(value) {
await (async () => {
const db = await open({
filename: dbFile,
driver: sqlite3.Database
})
const row = await db.get(`SELECT id FROM Users WHERE name LIKE "${value}"`)
console.log(row.id)
return row.id
})()
}
async function add(req, res) {
var id = await add_value(req.body.value)
console.log(id)
}
I'm pretty sure the code is running asynchronously as desired - it's just that you aren't returning anything from add_user. For a smaller example:
async function someFn() {
await somePromise;
}
Above, someFn will always return a Promise that resolves to undefined, because nothing was returned from someFn. You're running into the same issue.
Use instead
async function add_user(value) {
const db = await open({
filename: dbFile,
driver: sqlite3.Database
})
const row = await db.get(`SELECT id FROM Users WHERE name LIKE "${value}"`)
console.log(row.id)
return row.id
}
I am new to await/async in Jquery. When I am trying to use it in my js file, It is getting executed, but not as expected.
async updateProduct (product) {
product.travelers.forEach((traveler, travelerOrder) => this.updateProductwithPassengerName(traveler) )
return product
}
async updateProductwithPassengerName (traveler) {
const travelerId = traveler.profile_id;
var body = await this.userServiceClient.request('/v2/users/' + travelerId + '/info','GET')
traveler.first_name = body.first_name
traveler.last_name = body.last_name
return traveler
}
async request (path, method, body) {
const options = {
method: method,
body: body,
headers: this.headers(),
credentials: 'same-origin'
}
const response = await fetch(this.relativeUrl(path), options)
if (!response.ok) {
throw new HttpError('Technical error occured', response.status)
}
return response.json().catch(function () {
throw new HttpError('No results found', response.status)
})
}
Those are the 3 functions. What is happening now is that
traveler.first_name = body.first_name
traveler.last_name = body.last_name
these are not setting in synchronous manner( after
var body = await this.userServiceClient.request('/v2/users/' +
travelerId + '/info','GET')
. These are executing after a quiet a long time.
What I am doing here is that, for each traveler I am setting first_name and last_name. And updating the product object. Since this setting of values is happening after a long time, product object is getting updated later, by the time UI page renders. I want this setting values to happening before doing anything else in jquery.
Looking for help
The problem is that forEach will not await the asynchronous result and so your first function returns a promise that immediately resolves, without waiting for the requests to finish.
Here is how to correct:
async updateProduct (product) {
await Promise.all(product.travelers.map((traveler, travelerOrder) => this.updateProductwithPassengerName(traveler) ));
return product
}
Or, if the backbone cannot deal with all these concurrent requests, then wait for each of them to complete before issuing the next:
async updateProduct (product) {
for (let traveler of product.travelers) {
await this.updateProductwithPassengerName(traveler);
}
return product
}
when using asyn/await in JQuery or angularjs or nodejs, use promise. Promise will complete the process and then return either success or fail. Then only execute next steps.Go through below links and you will get idea.
Modern Asynchronous JavaScript with Async and Await
async & await in Javascript
Edit2: Solution at the bottom
I am using the chrome-console and I am trying to output fetched data, and I only get the desired output by writing "await" at exactly the right place, even though another solution can do it earlier and I don't know why/how it works.
solution() is the "official" solution from a web-course I am doing. Both functions return the same, currently. In myFunction I tried writing "await" in front of every used function and make every function "async", but I still can't replace the "await" inside log, even though the other solution can.
const urls = ['https://jsonplaceholder.typicode.com/users']
const myFunction = async function() {
// tried await before urls/fetch (+ make it async)
const arrfetched = urls.map( url => fetch(url) );
const [ users ] = arrfetched.map( async fetched => { //tried await in front of arrfetched
return (await fetched).json(); //tried await right after return
});
console.log('users', await users); // but can't get rid of this await
}
const solution = async function() {
const [ users ] = await Promise.all(urls.map(async function(url) {
const response = await fetch(url);
return response.json();
}));
console.log('users', users); // none here, so it can be done
}
solution();
myFunction();
I would think "await" works in a way that makes:
const a = await b;
console.log(a); // this doesn't work
the same as
const a = b;
console.log(await a); // this works
but it doesn't, and I don't understand why not. I feel like Promise.all does something unexpected, as simply writing "await" in the declaration can't do the same, only after the declaration.
Edit1: this does not work
const myFunction = async function() {
const arrfetched = await urls.map( async url => await fetch(url) );
const [ users ] = await arrfetched.map( async fetched => {
return await (await fetched).json();
});
console.log('users', users);
}
Edit2: Thanks for the help everyone, I tried putting ".toString()" on a lot of variables and switching where I put "await" in the code and where not.
As far as I understand it, if I don't use Promise.all then I need to await every time I want to use (as in the actualy data, not just use) a function or variable that has promises. It is insufficient to only have await where the data is being procensed and not further up.
In the Edit1 above users runs bevore any other await is complete, therefore no matter how many awaits i write in, none are being executed. Copying this code in the (in my case chrome-)console demostrates it nicely:
const urls = [
'https://jsonplaceholder.typicode.com/users',
]
const myFunction = async function() {
const arrfetched = urls.map( async url => fetch(url) );
const [ users ] = arrfetched.map( async fetched => {
console.log('fetched', fetched);
console.log('fetched wait', await fetched);
return (await fetched).json();
});
console.log('users', users);
console.log('users wait', await users);
}
myFunction();
// Output in the order below:
// fetched()
// users()
// fetched wait()
// users wait()
TL; DR: Promise.all is important there, but it's nothing magical. It just converts an array of Promises into a Promise that resolves with an array.
Let's break down myFunction:
const arrfetched = urls.map( url => fetch(url) );
This returns an array of Promises, all good so far.
const [ users] = arrfetched.map( async fetched => {
return (await fetched).json();
});
You're destructuring an array to get the first member, so it's the same as this:
const arr = arrfetched.map( async fetched => {
return (await fetched).json();
});
const users = arr[0];
Here we are transforming an array of promises into another array of promises. Notice that calling map with an async function will always result in an array of Promises.
You then move the first member of that array into users, so users now actually contains a single Promise. You then await it before printing it:
console.log('users', await users);
In contrast, the other snippet does something slightly different here:
const [ users ] = await Promise.all(urls.map(async function(url) {
const response = await fetch(url);
return response.json();
}));
Once again, let's separate the destructuring:
const arr = await Promise.all(urls.map(async function(url) {
const response = await fetch(url);
return response.json();
}));
const users = arr[0];
Promise.all transforms the array of Promises into a single Promise that results in an array. This means that, after await Promise.all, everything in arr has been awaited (you can sort of imagine await Promise.all like a loop that awaits everything in the array). This means that arr is just a normal array (not an array of Promises) and thus users is already awaited, or rather, it was never a Promise in the first place, and thus you don't need to await it.
Maybe the easiest way to explain this is to break down what each step achieves:
const urls = ['https://jsonplaceholder.typicode.com/users']
async function myFunction() {
// You can definitely use `map` to `fetch` the urls
// but remember that `fetch` is a method that returns a promise
// so you'll just be left with an array filled with promises that
// are waiting to be resolved.
const arrfetched = urls.map(url => fetch(url));
// `Promise.all` is the most convenient way to wait til everything's resolved
// and it _also_ returns a promise. We can use `await` to wait for that
// to complete.
const responses = await Promise.all(arrfetched);
// We now have an array of resolved promises, and we can, again, use `map`
// to iterate over them to return JSON. `json()` _also_ returns a promise
// so again you'll be left with an array of unresolved promises...
const userData = responses.map(fetched => fetched.json());
//...so we wait for those too, and destructure out the first array element
const [users] = await Promise.all(userData);
//... et voila!
console.log(users);
}
myFunction();
Await can only be used in an async function. Await is a reserved key. You can't wait for something if it isn't async. That's why it works in a console.log but not in the global scope.
Ok so i've searched around and found nothing related to this problem.
My problem is something like this ->
I create an object (push into array) with some info taken from an api. After getting the info from the api i need to call yet another API to get further information on users. Since there are multiple keys for users i'd like to be able to set them inline with a simple function.
I'm doing something like this ->
_item.push({
Author: setPeople(item.Author.Title),
Title: item.Title,
....
Requester: setPeople(item.Requester.Title
})
At the moment i am getting the promise set(entirely) and not the PromiseValue. I know you usually do something like setPeople(name).then(() => {}) however that is not working in my object (sets the key too fast).
Any tip on how i should approach this?
Updating with more code.
export const retrieveIrfItems = async (spId) => {
let spQuery = "SITE" + SpQueryExtend1 + spQueryExpand;
return new Promise((resolve, reject) => {
let _items = [];
axiosApi.get(SiteUrl + spQuery).then((response) => {
//console.log(response.data.d);
return response.data.d;
}).then(async (item) => {
//let requesterSP = setPeople()
const createSPUser = async (user) => {
let spUser;
console.log("User prop is");
console.log(user);
setPeople(user).then((item) => {
spUser = item;
});
return spUser;
}
_item.push({
Author: setPeople(item.Author.Title),
Title: item.Title,
....
Requester: setPeople(item.Requester.Title
})
Ignore the unused function, i'm still doing tests to find a way for this problem.
Found the fix thanks to comments.
Using async/await wouldnt help me since i'd still get promise pending or undefined. What i had to use is ->
Requester: await setPeople(item.Requester.Title).then((user) => { return user }),
Using that in my object seems to work, but my question is...how good is this approach? If there are lots of fields with this behaviour (currently 5), wouldnt that slow down the page by...a lot ?
Then you should try something like that :
export const retrieveIrfItems = async (spId) => {
return new Promise((resolve, reject) => {
let spQuery = "SITE" + SpQueryExtend1 + spQueryExpand;
let _items = [];
try{
const axiosApiItem = await axiosApi.get(SiteUrl + spQuery);
const item = axiosApiItem.data.d;
_item.push({
Author: await setPeople(item.Author.Title),
Title: item.Title,
...
Requester: await setPeople(item.Requester.Title)
});
return resolve(_items);
}catch(e){
return reject(e);
}
});
}
Async / await is a way to consume async Promise functions. The async keyword tells the javascript compiler that this function will consume one or more asynchronous functions. The await keyword tells the compiler that the next function call is asynchronous and returns a promise.
In your code, your first then() function should return a promise which is not the case, that's why the second then() can't be reached.
Also, in your code, your new Promise doesn't return anything. When you create a new Promise, you have to end it by calling resolve() or reject.
Hope it helps...
I have went through some basic work on callback function and promise. But when I see the following code, I really can't find where did that zzz term come from.
I thought (zzz) is gonna be a input to callback function. inside the callback function, zzz was never defined.
return Dishes.find({}).exec() is only execution which returns nothing. even it returns something, it will go to output of the callback function instead of input, which is (zzz).
sorry if the question is stupid, i just looked at this point for 2 hours and can't figure out... thanks
const mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
const Dishes = require('./models/dishes');
const url = 'mongodb://localhost:27017/conFusion';
const connect = mongoose.connect(url, {
useMongoClient: true
});
connect.then((db) => {
console.log('Connected correctly to server');
var newDish = Dishes({
name: 'Uthappizza',
description: 'test'
});
newDish.save()
.then((zzz) => {
// ??? where did this zzz come from ??????????????????????????????????????????????
console.log(zzz);
return Dishes.find({}).exec();
})
.then((xxx) => {
console.log(xxx);
return db.collection('dishes').drop();
})
.then(() => {
return db.close();
})
.catch((err) => {
console.log(err);
});
});
Since the save() method is asynchronous it returns a Promise, and chaining it to the then() method you entered the callback function and passed it the ‘zzz’ argument.
‘zzz’ is the newDish object that you saved.
You can use the find({}).exec() in any case to find all objects in the database and execute a callback with the results.