This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 5 years ago.
I want to use Mongoose's bulk operation for upserting transactions. For each of my transactions I want to process them in a loop and within that loop I need to use a promise. After that promise resolved, I want to add the upsert to the bulk.
My problem here is, that although I await for every promise to finish, the bulk is executed at the end of the function before any of the promises is resolved. What am I doing wrong or how can I fix this?
const bulkTransactions = Transaction.collection.initializeUnorderedBulkOp();
transactions.forEach( async (transaction: any) => {
// do some suff, fill transaction_data
await Utils.processTransactionType(transaction).then((action: any) => {
if (action) {
// do other stuff
}
bulkTransactions.find({_id: hash}).upsert().replaceOne(transaction_data);
}).catch((err: Error) => {
// log error
});
});
await bulkTransactions.execute().catch((err: Error) => {
// log error
});
As far as I know, when using await, you no longer use the then return value:
const bulkTransactions = Transaction.collection.initializeUnorderedBulkOp();
transactions.forEach( async (transaction: any) => {
// do some suff, fill transaction_data
let action = await Utils.processTransactionType(transaction);
if (action) {
// do other stuff
}
bulkTransactions.find({_id: hash}).upsert().replaceOne(transaction_data);
});
await bulkTransactions.execute().catch((err: Error) => {
// log error
});
Related
This question already has answers here:
async/await implicitly returns promise?
(5 answers)
Closed 1 year ago.
When I console.log(data), I log the information I need, but if return the value of data in getWeather(), it just returns a pending promise. I have tried many things, but none have worked so far. I'll leave my broken code below.
const axios = require('axios');
const getWeather = async () => {
try {
let response = await axios.get(
'http://api.openweathermap.org/data/2.5/forecast?id=524901&appid={apiKey}'
);
let data = response.data;
return data;
} catch (e) {
console.log(e);
}
};
async function returnAsync() {
const x = await getWeather();
return x;
}
console.log(getWeather()); // returns a pending promise
console.log('check ', returnAsync()); // also returns a pending promise
async functions must return a promise. (they implicitly return Promise<void> instead of void!)
Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise.
For example, the following:
async function foo() {
return 1
}
...is equivalent to:
function foo() {
return Promise.resolve(1)
}
Source
This could be to do with the fact that you're trying to call an async function inside of a synchronous function. It's quite a common mistake to make, so don't fret. Typically if you think about the structure, the console logs could technically be run before the async function has completed. That's why we have "callback functions" which basically just run as soon as the async returns a value.
Axios has a really neat way to use these callbacks which is just using the .then() function.
So try this out and see if it works:
const axios = require('axios');
const getWeather = async () => {
axios.get('http://api.openweathermap.org/data/2.5/forecast?id=524901&appid={apiKey}')
.then(json => console.log(json))
.catch(error => console.log(error))
};
getWeather();
Because you're trying to call the get request inside of an async function, you cannot then grab the data in a synchronous function.
//const getWeather = async () => {...
An async function's return value will be a Promise which will be resolved with the value returned by the async function, or rejected with an exception thrown from, or uncaught within, the async function.
check more at
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
How do I access previous promise results in a .then() chain?
(17 answers)
Closed 2 years ago.
I'm developing a script that connects with an API, then with the JSON reponse do some operations and then reformat the JSON to send it to another API.
But now I'm stuck in the first step as I can't deal with the first part as my Promises is not working as expected. How can I store the API's response into a variable? For development puropose I stored one API response into a JSON file. This is my code:
declare var require: any;
let url = './data/big buy/big-bui-product-list.json';
const fs = require('fs');
let counter = 0;
const getProductList = () => {
return new Promise((resolve, reject) => {
fs.readFile(url, 'utf8', (err, data) => {
if(err){
return reject (err);
}
else {
return resolve(JSON.parse(data));
}
})
})
}
const getProductStock = () => {
return new Promise((resolve, reject) => {
fs.readFile('./data/big buy/big-bui-product-stock.json', 'utf8', (err, data) => {
if(err) {
return reject(err);
}
else {
return resolve(JSON.parse(data));
}
})
})
}
try {
let products;
console.log('Products:');
Promise.all([getProductList()])
.then(function(result) {
products = result[0];
});
console.log('Stocks:');
const productStock = Promise.all([getProductStock()]);
console.log(products);
}
catch(e) {
console.log((`Ha ocurrido un error: ${e.message}`));
}
finally {
}
In this code, what I do is getting a list of products and then get the stocks of all the products, later I will add a new function that will filter by stock and get me just a list of products where stock is bigger than X units. Now when I launch it from the terminal I dont' get the response stored into products variable but if I add .then((data) => console.log(data)) into the Promise I see on screen the JSON but as I dont' have it stored it in any variable I don't see how can I work with the objects I'm retrieving.
Promises are asynchronous. They are quite literally promises that a value will be yielded in the future. When you do getProductList().then(x => products = x), you're saying that Javascript should fetch the product list in the background, and once it's finished, it should set the products variable to x. The key words there are "in the background", since the code afterwards keeps running while the product list is being fetched. The products variable is only guaranteed to be set after the .then portion is run. So, you can move things into the .then:
try {
let products;
getProductList().then(list => {
products = list;
return getProductStock(); // leverage promise chaining
}).then(stocks => {
console.log("Products:", products);
console.log("Stocks:", stocks);
});
}
catch(e) {
console.log((`Ha ocurrido un error: ${e.message}`));
}
finally {
}
You seem to be missing some fundamental knowledge about promises. I suggest reading through the MDN Using Promises guide to familiarize yourself a bit with them.
A structure like below never works.
let variable;
promise.then(data => variable = data);
console.log(variable);
This is because it is executed in the following manner.
Create the variable variable.
Add a promise handler to the promise.
Log variable.
Promise gets resolved.
Execute the promise handler.
Set variable variable to data.
If you are using Node.js 10 or higher you can use the promise API of file system to simplify your code quite a bit.
const fs = require('fs/promises');
const readJSON = (path) => fs.readFile(path, "utf8").then((json) => JSON.parse(json));
const getProductList = () => readJSON("./data/big buy/big-bui-product-list.json");
const getProductStock = () => readJSON("./data/big buy/big-bui-product-stock.json");
Promise.all([
getProductList(),
getProductStock(),
]).then(([products, stocks]) => {
console.log({ products, stocks });
}).catch((error) => {
console.log("Ha ocurrido un error:", error.message);
}).finally(() => {
// ...
});
This question already has answers here:
map() function with async/await
(5 answers)
Closed 2 years ago.
I'd like to do some check on a file with Promises before processing it.
As I'm using Node JS, I'd like to do all the verification asynchronously since they're all independant.
However, I'd like to print all the errors at once (if they are some) for debugging purpose. So I need to wait for all the operation to be done before doing anything else. So I'm using the async/wait keywords.
Here's my code :
async function isValid(file) {
try {
const check = [
check1(file),
check2(file),
check3(file),
check4(file),
check5(file)
]
let results = check.map(async checking => (await checking))
console.log((await results));
} catch(e) {
console.log(e)
}
}
The thing is, what's outputted by the console.log is the following:
[
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> }
]
What I expected to get was the result of the checks() function, but they're still pending despite the await keywords present multiple times.
Do you know what's wrong I'm doing?
Thanks in advance.
I think you want to use Promise.all here. You don't actually have to do your .map logic to invoke each individual function and await it. As long as check(<file>) returns a Promise, just call Promise.all on them.
Example:
async function isValid(file) {
try {
const check = [
check1(file),
check2(file),
check3(file),
check4(file),
check5(file)
]
const results = await Promise.all(check);
console.log('results', results);
} catch (e) {
console.log(e)
}
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
I'm working on Ionic v4 with Angular.
In my project i use the BLE to communicate with a raspberry.
I have several step :
Search Device around me
Connect to this device
Activate Notification
Send Messages
Currently i have something like :
this.ble.scan().subscribe(result => {
if (device === theDeviceIWant) {
this.ble.connect(device.id).subscribe(result => {
this.ble.startNotification(infosaboutDevice).subscribe(result => {
// Message 1
this.ble.writeWithoutResponse(infos, message).then(result => {
// Message 2
this.ble.writeWithoutResponse(infos, message).then(result => {
// Message 3
this.ble.writeWithoutResponse(infos, message).then(result => {
// Message X
this.ble.writeWithoutResponse(infos, message).then(result => {
})
})
})
})
})
})
})
}
I want to do something like that :
this.myScan();
this.myConnect();
this.myNotification();
this.myMessage('Text 1');
this.myMessage('Text 2');
this.myMessage('Text X');
The probleme : My function ‘myConnect‘ don't wait the end of ‘myScan‘ to start. So somme stuff needed by ‘myConnect‘ is do in ‘myScan‘.
I already try to use ‘async/await‘ but does not work. I think i don't use it correctly :
await this.myConnect().then(async () => {
await this.myNotification().then(async () => {
await this.myMessage('03020000').then(async () => {
await this.myMessage('010100').then(async () => {
await this.myMessage('020200' + this.random.toString(16));
});
});
});
});
Help me to understand how to create a function who wait the end of the before one to start :D
Just use async/await OR then
await this.myConnect(); // this awaits the Promise returned by myConnect to be resolved
await this.myNotification(); // same for this Promise
await this.myMessage('03020000'); // and so on...
await this.myMessage('010100');
await this.myMessage('020200' + this.random.toString(16));
The keyword await makes JavaScript wait until that promise settles and
returns its result.
So you dont need to use then in await this.myConnect().then(()=>{});
use await this.myConnect();
Below is example which help you understand better
function SignalOne() {
return new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('Hello iam signal one');
}, 2000);
});
}
function SignalTwo() {
return new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('Hello iam signal Two');
}, 1000);
});
}
async function sendSignal() {
let one = await SignalOne();
let two = await SignalTwo();
console.log(one);
console.log(two);
}
sendSignal();
Try this:
async myScan() {
// do things
}
ngOnInit() {
const scan = this.myScan(); // myScan doesn't actually have to return here
await scan;
const connect = this.myConnect();
await connect;
// more stuff
}
This is essentially what Promises are made for.
A Promise is an object representing the eventual completion or failure
of an asynchronous operation.
You can read up about Promises here. Once you read thru that, I left an example for you below to demonstrate how to use a Promise:
//Wrap the operation you want to wait for in a Promise (in this case: setTimeout)
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('3 seconds have passed');
}, 3000);
});
//Once the operation is resolved the callback in the .then will be called
promise.then(val => document.querySelector('#target').innerHTML = val);
<div id="target">This message will change once the operation is resolved in 3 seconds.</div>
I would embrace Observables. Looking at what you want..
Search Device around me
Connect to this device
Activate Notification
Send Messages
1 and 2 would be chained with switchMap, as responses depend on each other. Then 3 and 4 could be performed in order, but not dependent on each other, therefore we could use concat with those. (If this is not correct flow, adjust accordingly with these two operators).
So I suggest the following:
import { never } from 'rxjs';
import { switchMap, concat } from 'rxjs/operators';
// ...
this.ble.scan().pipe(
switchMap((device) => {
if (device === theDeviceIWant) {
return this.ble.connect(device.id)
}
// terminates rest of code
return never();
}),
concat(
this.ble.startNotification(...),
this.ble.writeWithoutResponse(...)
)
).subscribe(data => console.log(data))
You're so close! Rather than using .then and async just use one or the other. Here are a few ways to accomplish what you are trying to do:
Using .then:
This is your typical chaining syntax. Promises can be chained using .then() and passing in a function. If the return value is a value (not a Promise) then it will resolve to that value. But if it did return a Promise then it will chain together and your next .then() will resolve to the "inner" async call result.
// Message 1
return this.ble.writeWithoutResponse(infos, message).then(result1 => {
// Message 2
return this.ble.writeWithoutResponse(infos, message);
}).then(result2 => {
// Message 3
return this.ble.writeWithoutResponse(infos, message);
)}.then(result3 => {
// Message X
return this.ble.writeWithoutResponse(infos, message);
}).then(result4 => { })
Using async/await
This approach achieves the same result but uses special keywords to automatically chain promises together. async/await allows you to skip the .then() and return calls so you can invoke your async functions as if they were synchronous.
// Message 1
let result1 = await this.ble.writeWithoutResponse(infos, message)
// Message 2
let result2 = await this.ble.writeWithoutResponse(infos, message);
// Message 3
let result3 = await this.ble.writeWithoutResponse(infos, message);
// Message X
let result4 = await this.ble.writeWithoutResponse(infos, message);
To learn more about Promise's and async javascript, check out these resources:
Promises on MDN
Promises on Google Web Fundamentals
Video on Async/Await
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
async/await implicitly returns promise?
(5 answers)
Closed 3 years ago.
In the below code snippet I am trying to understand why the function does not return the result of the promise.
It first logs Promise { <pending> }, then logs the response variable with the correct data from the AWS API describing the table.
Why is it doing this? I've tried wrapping the function in another async function and awaiting it and I get the same result.
const AWS = require('aws-sdk');
AWS.config.update({region: 'eu-west-2'});
const docClient = new AWS.DynamoDB;
async function describeTable() {
const params = {
TableName: 'weatherstation_test',
};
let response;
try {
response = await docClient.describeTable(params).promise();
console.log(response); // This logs second. It logs the data correctly
} catch (e) {
console.error(e)
throw e;
}
return response;
}
console.log(describeTable()); // This logs first. It logs Promise { <pending> }
Update
This still returns Promise { <pending> } even if I add .then(result => result).