I'm new with async/await and I need a litle help.
What I would like to achive is to send and axios post request after a while loop finished.
How can I put the while loop in an async function and await for it?
This is the current code:
showResults: function () {
let vm = this;
let apiUrl = '/api/test';
let randomCallCount = Math.floor(Math.random() * (80 - 50 + 1) + 50);
let start = 1;
while (start <= randomCallCount) {
let randomChars = [...Array(40)].map(i => (~~(Math.random() * 36)).toString(36)).join('');
fetch('https://' + randomChars + '.ipleak.net/json/?query_type=mydns')
.then((resp) => resp.json())
.then(function (data) {
vm.dnsResult.push(data);
});
start++;
}
axios.post(apiUrl, {lat: vm.geoLat, lon: vm.geoLon, dns: vm.dnsResult})...
I thought maybe something like this, but this one is not working:
fetchDNSData: async function () {
let vm = this;
let promise = new Promise((resolve, reject) => {
let randomCallCount = Math.floor(Math.random() * (80 - 50 + 1) + 50);
let start = 1;
while (start <= randomCallCount) {
let randomChars = [...Array(40)].map(i => (~~(Math.random() * 36)).toString(36)).join('');
fetch('https://' + randomChars + '.ipleak.net/json/?query_type=mydns')
.then((resp) => resp.json())
.then(function (data) {
vm.dnsResult.push(data);
});
start++;
}
});
let result = await promise; // wait until the promise resolves (*)
return result;
},
showResults: function () {
let vm = this;
let apiUrl = '/api/test';
vm.fetchDNSData().then(
response => {
axios.post(apiUrl, {lat: vm.geoLat, lon: vm.geoLon, dns: vm.dnsResult})...
Any suggestion what can show me the right direction? :) Thanks a lot
If you are going to use async/await, you should not use then. Use await instead of then.
The below example should be what you need.
showResults: async function () {
let vm = this;
let apiUrl = '/api/test';
let randomCallCount = Math.floor(Math.random() * (80 - 50 + 1) + 50);
let start = 1;
while (start <= randomCallCount) {
let randomChars = [...Array(40)].map(i => (~~(Math.random() * 36)).toString(36)).join('');
const response = await fetch('https://' + randomChars + '.ipleak.net/json/?query_type=mydns');
const data = await response.json();
vm.dnsResult.push(data);
start++;
}
axios.post(apiUrl, {lat: vm.geoLat, lon: vm.geoLon, dns: vm.dnsResult})...
Related
This code works, I just need help with argument passing.
Goal:
To pass arguments to promises while iterating through a for loop. The arguments to pass are named folder, subfolder, pastsearch. The promises are called p1 and p2
What the Code does
This code works. Each promise takes a search term, looks for it in
its file and returns "yes" or "non" if file is there or not.
Promise.all prints a single line of yes/non to a file and
prints the total count of "yes" to another file.
CODE
const fs = require('fs');
const readline = require('readline')
const task_id = 1;
let folder = 1;
let subfolder = 1;
let pastsearch = 1;
const myarray = [6567, 50105, 67637, 293697];
const mylen = myarray.length;
const myfiles = ['file_1.txt', 'file_2.txt'];
fs.writeFile('/pathtomyfile/', '', function() {
console.log('done')
})
fs.writeFile('/pathtomyfile/', '', function() {
console.log('done')
})
const p1 = new Promise((resolve, reject) => {
let lineCount = 0;
let v = 0;
let yesnon = "non";
let readStream = readline.createInterface({
input: fs.createReadStream('/pathtofile/round_' + task_id + '/threehundred_' + folder + '/' + subfolder + '/' + myfiles[0], 'utf8')
});
readStream.on("line", (line) => {
lineCount++;
if (line == pastsearch) {
yesnon = "yes";
v++;
}
});
readStream.on('end', () => {
console.log('end');
readStream.destroy();
});
readStream.on("close", () =>
resolve({
yesnon
})
)
});
const p2 = new Promise((resolve, reject) => {
let readStream = readline.createInterface({
input: fs.createReadStream('/pathtofile/round_' + task_id + '/threehundred_' + folder + '/' + subfolder + '/' + myfiles[1], 'utf8')
});
let lineCount = 0;
let v = 0;
let yesnon = "non";
readStream.on("line", (line) => {
lineCount++;
if (line == pastsearch) {
yesnon = "yes";
v++;
}
});
readStream.on('end', () => {
console.log('end');
readStream.destroy();
});
readStream.on("close", () =>
resolve({
yesnon
}))
});
for (let h = 0; h < 3; h++) {
folder++
subfolder++
pastsearch = myarray[h];
Promise.all([p1, p2]).then((results) => {
const output = results.map(({
yesnon
}) => yesnon).join(' ');
fs.appendFileSync('/pathtofile/plain_round' + task_id + '.txt', output + "\n", 'utf8');
const output2 = results.map(({
yesnon
}) => yesnon);
let count = 0;
function countValues(array, countItem) {
array.forEach(itm => {
if (itm == countItem) count++;
});
return count;
}
const myresult34 = countValues(output2, "yes");
fs.appendFileSync('/pathtofile/round' + task_id + '.txt', myresult34 + "\n", 'utf8');
});
}
Note:
I am new to nodejs, mostly php experience, so I wrote this the best that I could from studying stackoverflow Q/A Posts.
Wrap your promises in a function that takes folder, subfolder, and pastsearch as arguments. For example with p1:
const p1 = (folder, subfolder, pastsearch) {
return new Promise((resolve, reject) => {
// `folder`, `subfolder` and `pastsearch` are available here
}
}
Then invoke p1 inside Promise.all:
Promise.all([p1(folder, subfolder, pastsearch), p2]).then((results) => {
In javascript this technique is called closure
This question already has an answer here:
Getting Promise pending ..- ES6
(1 answer)
Closed 12 months ago.
When running the below code and dumping out the results variable it returns Promise {<pending>}, I have added the await key word to the being of the function call so const results = await getAllResults() however this returns the error of Unexpected reserved word 'await'.
Anyone have any ideas?
useEffect(() => {
async function getPageOfResults(page) {
const response = await axios.get('https://swapi.dev/api/starships/?page=' + page);
return response.data.results;
}
async function getAllResults() {
let starships = [];
let lastResultsLength = 10;
let page = 1;
while (lastResultsLength === 10) {
const newResults = await getPageOfResults(page);
page++;
lastResultsLength = newResults.length;
starships = starships.concat(newResults);
}
return starships;
}
const results = getAllResults();
}, []);
You need to add async in the useEffect like so:
useEffect(async () => {
async function getPageOfResults(page) {
const response = await axios.get('https://swapi.dev/api/starships/?page=' + page);
return response.data.results;
}
async function getAllResults() {
let starships = [];
let lastResultsLength = 10;
let page = 1;
while (lastResultsLength === 10) {
const newResults = await getPageOfResults(page);
page++;
lastResultsLength = newResults.length;
starships = starships.concat(newResults);
}
return starships;
}
const results = await getAllResults();
}, []);
async function getChampionID(randomChampionID) {
let response = await fetch('http://ddragon.leagueoflegends.com/cdn/11.10.1/data/en_US/champion.json');
let body = await response.json();
var championData = Object.keys(body.data)
var randomChampionKey = Math.floor(Math.random() * (154 - 0 + 1) + 0)
return randomChampionID = championData[randomChampionKey]
}
async function getChampionName(randomChampionName) {
let result = await getChampionID();
let response = await fetch(`http://ddragon.leagueoflegends.com/cdn/11.10.1/data/en_US/champion/${result}.json`)
let body = await response.json();
return randomChampionName = body.data[result].name
}
var randomChampion = document.getElementById('random-champion')
var bgimg = document.getElementById('background-image')
var championSquare = document.getElementById('square')
randomChampion.addEventListener("click", async () =>
{
let championID = await getChampionID()
let championName = await getChampionName()
bgimg.style.backgroundImage = `url('http://ddragon.leagueoflegends.com/cdn/img/champion/splash/${championID}_0.jpg')`
championSquare.src=`http://ddragon.leagueoflegends.com/cdn/11.11.1/img/champion/${championID}.png`
console.log(championID)
console.log(championName)
})
The getChampionName() function takes a random value from getChampionID, so whenever I call both of them through a button event listener, the getChampionID() generates a random ID (#1), the getChampionName() once again takes another value from getChampionID(), result in a different ID (#2), but I need the getChampionName() to take the #1 ID
Firstly, the functions are not being passed a parameter and therefore do not need anything within the parentheses when being defined.
Secondly, within the event listener, I would simply call a function called getChampion that gets a random ID, then gets the details, and returns both the champion detail and the ID for further use as an object.
My code would look like this.
async function getChampionID() {
let response = await fetch('http://ddragon.leagueoflegends.com/cdn/11.10.1/data/en_US/champion.json');
let body = await response.json();
var championData = Object.keys(body.data)
var randomChampionKey = Math.floor(Math.random() * (154 - 0 + 1) + 0)
return championData[randomChampionKey]
}
async function getChampion() {
let result = await getChampionID();
let response = await fetch(`http://ddragon.leagueoflegends.com/cdn/11.10.1/data/en_US/champion/${result}.json`)
let body = await response.json();
return { name: body.data[result].name, id: result }
}
var randomChampion = document.getElementById('random-champion')
var bgimg = document.getElementById('background-image')
var championSquare = document.getElementById('square')
randomChampion.addEventListener("click", async () =>
{
let champion = await getChampion()
bgimg.style.backgroundImage = `url('http://ddragon.leagueoflegends.com/cdn/img/champion/splash/${champion.id}_0.jpg')`
championSquare.src=`http://ddragon.leagueoflegends.com/cdn/11.11.1/img/champion/${champion.id}.png`
console.log(champion.id)
console.log(champion.name)
})
Imagine for example that you want to store paginated data from an API to a database.
let db;
let pageitems = 35
var offset = 0;
dbConnect //establish connection to database
.then( fetch(apiLink+?offset=2)
.then( res => res.json())
.then( res => {
var total = res.count
return collection.insertMany(res.data, {ordered: false})
// If offset is less than total, I want to increase offset and go back to the fetch-event.
.catch( err => {
if(err.code !== 11000){log(err)}
else{log({completed: err.result.nInserted, duplicates:
err.result.result.writeErrors.length});}
})
.then(() => {
connection.close();
})
You could just use a regular loop:
(async function() {
const conn = await dbConnect;
for(let offset = 0; true; offset++) {
const { data, count } = await (await fetch(`api?page=${offset}`)).json();
// Exit if the page is empty
if(count === 0) break;
await collection.insertMany(data, { ordered: false });
}
})();
To speed that up you could execute multiple requests in parallel:
const chunkSize = 10; // 10 in parallel
for(let offset = 0; offset < chunkSize; offset++) {
(async function() {
const conn = await dbConnect;
for(let offset2 = 0; true; offset2 += chunkSize) {
const { data, count } = await (await fetch(`api?page=${offset + offset2}`)).json();
// Exit if the page is empty
if(count === 0) break;
await collection.insertMany(data, { ordered: false });
}
})();
}
Basically, you will want to wrap your fetch and insert into a function that you will call many times. See the below as an example to illustrate my point...
let db;
let pageitems = 35
var offset = 0;
var db = dbConnect() //establish connection to database
function fetch_and_insert(offset) {
db
.then(fetch(apiLink + "?" + offset))
.then(res => res.json())
.then(res => {
var total = res.count
collection.insertMany(res.data, { ordered: false })
.catch(err => {
if (err.code !== 11000) { log(err) }
else {
log({
completed: err.result.nInserted, duplicates: err.result.result.writeErrors.length
});
}
})
if (offset < total) return fetch_and_insert(offset + pageitems)
return null;
})
}
fetch_and_insert(offset)
.then(() => {
connection.close();
})
I have the next function in my WebApp with Firebase:
function loadMonthData(){
let ganancias = 0;
let perdidas = 0;
let thisMonth = new Date();
thisMonth.setHours(0);
thisMonth.setMinutes(0);
thisMonth.setMilliseconds(0);
thisMonth.setDate(1);
fireIngresos.orderByChild('timestamp')
.startAt(thisMonth.getTime())
.once('value')
.then((snapshot)=>{
snapshot.forEach((ingreso)=>{
ganancias += ingreso.val().cash;
});
});
fireGastos.orderByChild('timestamp')
.startAt(thisMonth.getTime())
.once('value')
.then((snapshot)=>{
snapshot.forEach((perdida)=>{
perdidas += perdida.val().cash;
});
});
return ganancias - perdidas;
}
This get the sum of the property cash of all elements in my references fireIngresos and FireGastos (from the beginning of the month), then this return the difference of the two results.
The problem (evidently) is the promises ¿How can I do this correctly?
You can use async/await, return a value from .then()
async function loadMonthData(){
let ganancias = 0;
let perdidas = 0;
let thisMonth = new Date();
thisMonth.setHours(0);
thisMonth.setMinutes(0);
thisMonth.setMilliseconds(0);
thisMonth.setDate(1);
return await fireIngresos.orderByChild('timestamp')
.startAt(thisMonth.getTime())
.once('value')
.then(snapshot => {
snapshot.forEach(ingreso => {
ganancias += ingreso.val().cash;
});
return ganacias
})
- await fireGastos.orderByChild('timestamp')
.startAt(thisMonth.getTime())
.once('value')
.then(snapshot => {
snapshot.forEach(perdida => {
perdidas += perdida.val().cash
});
return peridadas
});
}
loadMonthData().then(result => {// do stuff with result});
function promise(n) {
return new Promise(resolve =>
setTimeout(resolve, Math.floor(Math.random() * 1000), n)
).then(data => data)
}
async function diff() {
return await promise(2 * 4) - await promise(2 * 2);
}
diff().then(res => console.log(res)); // 4