Can't assign value to a variable from array - javascript

I'm creating a simple project in JavaScript and can't seem to figure out why this is not working for me. I created a function that fetches an API to get a random country name, and then push that country name in to an empty array, but I can't seem to figure out how to assign value to my variable from that array, probably missing something easy here.
getRandomWord();
getRandomWord();
getRandomWord();
getRandomWord();
const words = [];
let selectedWord = words[Math.floor(Math.random() * words.length)];
console.log(words);
console.log(selectedWord);
// Fetch some random words
async function getRandomWord() {
const res = await fetch('https://randomuser.me/api');
const data = await res.json();
const randomWord = data.results[0].location.country;
words.push(randomWord);
}
I need to assign one random country name from words array to selectedWord but it throws undefined all the time, although I see 4 different country names in words array at locations from 0 to 3. Can someone explain this to me or maybe have even a better approach for this. Thanks !

Ok , so i changed code a bit.
async function getRandomWord() {
try {
const res = await fetch('https://randomuser.me/api');
const data = await res.json();
const randomWord = data.results[0].location.country;
return randomWord.toUpperCase();
// words.push(randomWord.toUpperCase());
} catch (e) {
console.log(
'There has been a problem with your fetch operation: ' + e.message
);
}
}
And then just called
(async () => {
selectedWord = await getRandomWord();
displayWord();
})();
Can't believe i did this :D Thanks.

The fetches have not resolved and words[] has not been populated when selectedWords = executes. Using Promise.all and then:
const p = Promise.all([
getRandomWord(),
getRandomWord(),
getRandomWord(),
getRandomWord()
]);
const words = [];
p.then(()=>{
const selectedWord = words[Math.floor(Math.random() * words.length)];
console.log(words);
console.log(selectedWord);
});
// Fetch some random words
async function getRandomWord() {
const res = await fetch('https://randomuser.me/api');
const data = await res.json();
const randomWord = data.results[0].location.country;
words.push(randomWord);
}
Note: You will want to use Promise.allSettled if you don't want the fail fast behavior, where any failure will cause it to return immediately. Also notice I'm using Promise.all so that it will run the fetches concurrently instead of waiting on them sequentially.
async/await instead of then
(async()=>{
let words = [];
for(var i = 0; i < 4; i++)
words.push(getRandomWord());
words = await Promise.all(words);
const selectedWord = words[Math.floor(Math.random() * words.length)];
console.log(words);
console.log(selectedWord);
})()
// Fetch some random words
async function getRandomWord() {
const res = await fetch('https://randomuser.me/api');
const data = await res.json();
const randomWord = data.results[0].location.country;
return randomWord;
}

Related

iterating Javascript array and delete based on condition

I want to iterate through an array of words, look up the definition and delete the word if no definition is found.
my code looks as follows;
var words = ["word1", "word2", "word3",]
function Meaning(words){
const getMeaning = async () => {
const response = await fetch(`https://api.dictionaryapi.dev/api/v2/entries/en/${words}`)
const myJson = await response.json()
for(i = 0; i < words.length; ++i) {
if(!response[i]){
myJson.splice(i,1)
console.log(myJson)
}
}}
This is not really doing anything atm. Where am I going wrong?
edit to add context
tried like this as well;
for(i = 0; i < words.length; ++i)
fetch(`https://api.dictionaryapi.dev/api/v2/entries/en/${words[i]}`).then((response) => {
if (response === 404) {
let response = words
words[i].splice(i,1)
console.log(response)
}
throw new Error('Something went wrong');
})
.then((responseJson) => {
let response = words
response[i].splice(i,1)
})
.catch((error) => {
console.log(error)
});
I can print out the 404 error when it finds no definition, but I can't remove it from the words array
After quick look at the API, and it appears to handle only single words, so the caller needs to make the requests one at a time. Here's how to do it...
const baseUrl = 'https://api.dictionaryapi.dev/api/v2/entries/en/';
// one word lookup. resolve to an array of definitions
async function lookupWord(word) {
const res = await fetch(baseUrl + word);
return res.json();
}
// resolve to a bool, true if the word is in the corpus
async function spellCheck(word) {
const defArray = await lookupWord(word);
return Array.isArray(defArray) && defArray.length > 0;
}
// create a spellCheck promise for every word and resolve with the results
// note, this mutates the array and resolves to undefined
async function spellCheckWords(array) {
const checks = await Promise.all(array.map(spellCheck));
for (let i=array.length-1; i>=0; i--) {
if (!checks[i]) array.splice(i,1);
}
}
// test it (a little)
let array = ['hello', 'whereforeartthou', 'coffee'];
spellCheckWords(array).then(() => {
console.log(array)
})
try this code, you need to check every single element of array from response
var words = ["word1", "word2", "word3"];
function Meaning(words) {
const getMeaning = async () => {
const response = await fetch(`https://api.dictionaryapi.dev/api/v2/entries/en/${words}`)
const myJson = await response.json()
let result = [];
myJson.forEach(element => {
if(words.includes(element)) {
result.push(element)
}
});
return result;
}
return getMeaning();
}

JSON.stringify won't work on JSON Object where properties are created with Object.defineproperty

I'm currently writing a web scraping discord bot and want to implement the logic. I create the final Object it also has all properties that i set but when i try to console.log(totalData) it returns {}
same result when i do console.log(JSON.stringify(totalData)) => {}
i have also tried it with console.dir(), console.table()
The code:
const puppeteer = require('puppeteer')
let url = "https://www.worldometers.info/coronavirus/";
async function scrapeAllByCountry(page, country){
const totalData = {}
let endPosition;
// XPath to the data
allData = ["/html/body/div[3]/div[3]/div/div[6]/div[1]/div/table/tbody[1]"]
headerData = ["Country", "Total Cases", "New Cases", "Total Deaths", "New Deaths", "Total Recovered", "New recovered", "Active Cases", "Serious, Critical", "Total Cases/1M pop", "Deaths/1M pop", "Total Tests", "Tests/1M pop", "Population"]
// scraping the data
var element = await page.waitForXPath(allData[0])
let allTableData = await page.evaluate(element => element.textContent, element)
allTableData = allTableData.toLowerCase()
// replacing comma with nothing so numbers return false when i call isNaN()
allTableData = allTableData.replaceAll(",", "")
// searches for the country in the string and saves it into positionCountry
let positionCountry = allTableData.search(country.toLowerCase())
// Adds 150 more chars so the full Data is in it
let data = allTableData.substring(positionCountry, positionCountry + 150)
// creates array for each row
tempDataArray = data.split("\n");
// searches for the next NAN in the array and sets the end position
for(let i = 0; i < tempDataArray.length; i++){
// if the current element is a number do nothing if it is a NaN set endPosition and exit
if(isNaN(tempDataArray[i]) & i != 0){
endPosition = i
break;
}
}
// create new Array with endposition
let filteredArray = [];
for(let i = 0; i < endPosition; i++){
filteredArray.push(tempDataArray[i])
}
// Merge both Arrays into Object
for(let i = 0; i < filteredArray.length; i++){
// sets the header with a value on the totalDataObject
Object.defineProperty(totalData, headerData[i], {
value: filteredArray[i],
writable: false
})
// here it confirms that it has all Properties
console.log(totalData.hasOwnProperty(headerData[i]))
}
console.log(JSON.stringify(totalData)) // outputs {}
return totalData
}
async function main(){
const browser = await puppeteer.launch({})
const page = await browser.newPage()
await page.goto(url)
let result = await scrapeAllByCountry(page, "Germany")
console.log(JSON.stringify(result)) // also returns {}
console.log(result.hasOwnProperty("Country"))
browser.close()
}
main();

How to write array data to json?

How to write the data that the loop passes to the array "eventsPolygon", to json. This array returns 4 args. With this method, I get the error "TypeError [ERR_INVALID_CALLBACK]: Callback must be a function. Received undefined"
async function main() {
console.log("Start checking rewards")
const currentBlockNumberPolygon = await maticProvider.getBlockNumber() - 1
const currentBlockNumberBsc = await bscProvider.getBlockNumber() - 1
const oldestBlockNumberPolygon = 22939848
const oldestBlockNumberBsc = 13763979
const eventFilterPolygon = Missions.filters.RewardToPay()
const eventFilterBsc = Rewards.filters.RewardPayed()
let eventsPolygon = []
let eventsBsc = []
for (let i = oldestBlockNumberPolygon; i < currentBlockNumberPolygon - 10000; i += 10000) {
const eventsLoop = await Missions.queryFilter(eventFilterPolygon, i, i + 10000)
eventsPolygon = eventsPolygon.concat(eventsLoop)
const jsonData = JSON.stringify(eventsPolygon);
fs.writeFile('eventsBsc.json', jsonData.finished)
console.log(i)
}
//for(let i = oldestBlockNumberBsc; i < currentBlockNumberBsc-10000; i+=10000) {
//const eventsLoop = await Rewards.queryFilter(eventFilterBsc, i, i+10000)
// eventsBsc = eventsBsc.concat(eventsLoop)
//console.log(i)
//}
console.log('a')
}
JSON.stringify returns a string representation of your JSON. So you cannot do this:
fs.writeFile('eventsBsc.json', jsonData.finished)
Simply write jsonData to the file:
await fs.writeFile('eventsBsc.json', jsonData);
Be aware that this function is async. You need to await it

Javascript "for of" loop not returning value

async function getMultiBalances() {
let chains = await getAllChains();
let address = await getAddress();
let totalBalances = [];
for (let chain of chains) {
let chainId = chain.chain_id;
let balances = await getMultichainBalancesArray(chainId, address);
if (balances != undefined) {
totalBalances = [...balances, ...totalBalances];
}
}
console.log(totalBalances);
return totalBalances;
}
The above code console logs nothing and returns nothing.
Now.. If I move the console log and return statement into the "for of" loop it will return the first iteration and work fine. I don't understand why I can't return the final value outside of the for of loop to get the array I actually want.
async function getMultiBalances() {
let chains = await getAllChains();
let address = await getAddress();
let totalBalances = [];
for (let chain of chains) {
let chainId = chain.chain_id;
let balances = await getMultichainBalancesArray(chainId, address);
if (balances != undefined) {
totalBalances = [...balances, ...totalBalances];
}
console.log(totalBalances);
return totalBalances;
}
}

Calling promise-driven functions regularly with setInterval and operating over its results

My goal is to make a video playlist generator that runs at specific times, along with a running clock and many other things that run periodically, but I'm stuck at the part where it generates the playlist at the times I define.
I'm using FileHound to walk a folder, which works whenever I call the find() method, but as it's Promise driven, its results aren't readily available to be used by the following console.log(), for example. Same thing happens with MediaInfo(), but this time I was able to work around it with async/await, which as far as I know is the actual way to use a Promise based function.
Now, as far as I can understand, the .each() and .then() method chaining are the ways to use the results from a Promise driven function, but that would quickly result in code repetition for every time I want to do the same thing in different places.
All being said, I think I'm off my track by very far, and despite my efforts I can't seem to find a clear way to achieve what I want, so I'm asking for help. This is the code I have so far, and I'm using the following npm packages:
node-mediainfo
filehound
moment
const MediaInfo = require("node-mediainfo");
const Path = require("path");
const FileHound = require("filehound");
const Moment = require("moment");
const START_TIME = Moment();
const END_TIME = null;
const VIDEO_PATH = "videos";
let files = FileHound.create()
.path(VIDEO_PATH)
.depth(0);
let playlist = [];
let start_time = START_TIME.add(10, "seconds");
const ArrayShuffle = (array) => {
for (let i = array.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
};
const MakePlaylist = async (file) => {
let fileinfo = await MediaInfo(Path.resolve(file));
let duration = fileinfo.media.track[0].Duration;
let title = fileinfo.media.track[0].Title || Path.basename(file, Path.extname(file));
let artist = fileinfo.media.track[0].Performer || null;
playlist.push({
path : Path.resolve(file),
title : title,
artist : artist,
duration: duration
});
};
console.log(start_time.toLocaleString());
/* Main Loop */
setInterval(() => {
if (Moment().isSame(start_time)) {
console.log("First Run");
files.find().each(MakePlaylist).then(ArrayShuffle);
console.log(playlist);
}
if (Moment().isSame(Moment(start_time).add(30, "seconds"))) {
console.log("Second Run");
playlist = [];
files.find().each(MakePlaylist).then(ArrayShuffle);
console.log(playlist);
}
}, 1);
I would be tempted to put your logic into an async function, making use of await. and then simply recall your function later, instead of trying to do it in setTimeout
Assuming files.find() returns a promise....
const GeneratePlaylist = async () => {
var files = await files.find();
var playlist = [];
for(var i=0;i<files.length;i++){
playlist.push(await MakePlaylist(files[i]));
}
ArrayShuffle(playlist);
return playlist;
}
Then you can use that from another async function, and you can recall it 1ms later with setTimeout (Note, you should make MakePlaylist return the new item, not push to a global array):
const doMyThing = async (){
if (Moment().isSame(start_time)) {
console.log("First Run");
playlist = await GeneratePlaylist();
console.log(playlist);
}
if (Moment().isSame(Moment(start_time).add(30, "seconds"))) {
console.log("Second Run");
playlist = [];
playlist = await GeneratePlaylist();
console.log(playlist);
}
setTimeout(doMyThing,1);
}
Below is a working example, where I've just faked up some of your functionality using Promises to simulate asynchronous work like finding files and loading the media info:
const ArrayShuffle = (array) => {
for (let i = array.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
};
const MakePlaylist = async (file) => {
let fileinfo = await new Promise(resolve => setTimeout(() => resolve({media:{track:[{Duration:1,Title:"Title",Performer:"Foo"}]}}),1000));
let duration = fileinfo.media.track[0].Duration;
let title = fileinfo.media.track[0].Title || Path.basename(file, Path.extname(file));
let artist = fileinfo.media.track[0].Performer || null;
return{
path : file,
title : title,
artist : artist,
duration: duration
};
};
const findFileMockup = () => {
return new Promise(resolve => setTimeout(() => {
resolve(["file1.txt","file2.txt","file3.txt"]);
},500));
}
const GeneratePlaylist = async () => {
var files = await findFileMockup(); // await files.find() in your code
var playlist = [];
for(var i=0;i<files.length;i++){
playlist.push(await MakePlaylist(files[i]));
}
ArrayShuffle(playlist);
return playlist;
}
const test = async () => {
var playlist = await GeneratePlaylist();
console.log(playlist);
}
test();

Categories

Resources