How to only execute a function once in Javascript? - javascript

I have an if else statement in my main function, when the if statement is true I want to continue another function inside the if statement.
However the if statement stays true until a transaction is confirmed, which leads to retrigger the 2nd function to be executed more than once.
The buyToken function gets executed inside the if statement of the mempool function
async function buyToken(){
try{
const value = '1000000000000000'
const amountOut = await routerContract.getAmountsOut(value,[wbnb, tokenToFrontRun] )
console.log(ethers.utils.formatEther(amountOut[0]))
console.log(ethers.utils.formatUnits(amountOut[1], 9))
const buy = await routerContract.swapExactETHForTokensSupportingFeeOnTransferTokens(
0,
[wbnb, tokenToFrontRun],
address,
Date.now() + 1000 *60*3,
{
'value':value,
'gasPrice':ethers.utils.parseUnits('80', 'gwei'),
'gasLimit':300000
}
)
receipt = await buy.wait()
console.log(receipt.transactionHash)
return
}catch(e){
console.log(e)
}
}
async function mempool(){
provider.on("pending", async(tx)=>{
const txInfo = await provider.getTransaction(tx);
try{
//console.log(txInfo.to)
if(toChecksumAddress(txInfo.to) == routerAddress){
console.log("to uniswap router")
const iface = new ethers.utils.Interface(routerAbi);
let decodedData = iface.parseTransaction({ data: txInfo.data});
const valueSent = ethers.utils.formatUnits(txInfo.value, 'ether')
const first = decodedData.args.path[0]
const lastItem = decodedData.args.path
const last = lastItem[lastItem.length -1]
if(toChecksumAddress(first) == wbnb && toChecksumAddress(last) == tokenToFrontRun ){
console.log(txInfo);
console.log(ethers.utils.formatEther(txInfo.value))
console.log(ethers.utils.formatUnits(txInfo.gasPrice, 'gwei'))
// console.log(ethers.utils.formatUnits(txInfo.gasLimit, 'gwei'))
console.log(txInfo.confirmations)
console.log(txInfo.from)
console.log("front running transaction")
await buyToken()
}
}
}
catch (e){
//console.log("no data to show");
//console.log(e)
}
})
}
mempool()
So how can I make it so that the buyToken function is only executed once?
I know there are plenty of tutorials on w3schools, but this doesn't really help me in this case.

Define the buyToken function as an arrow function.
let buyToken = async () => {
// your logic
}
Then in the event,
if (buyToken)
await buyToken();
buyToken = null;
But, in ethers.js instead of using on, you can use once to call the method once.
So, in your case,
provider.once("pending", async(tx)=>{
// your logic
})

Related

async/await logs to the console but returns no value and returns `Promise { pending }`

I have been trying to get the result of this asynchronous function to no degree of success for the past few hours. I have checked the past similar questions and solutions but nothing has worked for this specific case.
This particular code below logs the value when I run console.log:
const okay = async () => {
console.log(await getTimezoneLabel(timezone));
};
okay();
The code below logs Promise {pending} instead of a value to the console which is baffling
const okay = async () => {
return await getTimezoneLabel(timezone);
};
let result = okay();
console.log(result);
Here is the getTimezoneLabel function itself:
async function getTimezoneLabel(timezone) {
const timezoneObject = await convertTimezone('original', timezone);
return timezoneObject[0].label;
}
Here is the convertTimezone function which the getTimezoneLabel function references:
import timezonesList from '../timezone-list';
async function convertTimezone(labelStyle, timezone) {
const spacetime = (await import('spacetime')).default;
const soft = (await import('timezone-soft')).default;
const timezones = Object.fromEntries(Object.entries(timezonesList).filter(([key]) => key.includes(timezone)));
return Object.entries(timezones)
.reduce((selectOptions, zone) => {
const now = spacetime.now(zone[0]);
const tz = now.timezone();
const tzStrings = soft(zone[0]);
let label = '';
let abbr = now.isDST()
? // #ts-expect-error
tzStrings[0].daylight?.abbr
: // #ts-expect-error
tzStrings[0].standard?.abbr;
let altName = now.isDST() ? tzStrings[0].daylight?.name : tzStrings[0].standard?.name;
const min = tz.current.offset * 60;
const hr = `${(min / 60) ^ 0}:` + (min % 60 === 0 ? '00' : Math.abs(min % 60));
const prefix = `(GMT${hr.includes('-') ? hr : `+${hr}`}) ${zone[1]}`;
switch (labelStyle) {
case 'original':
label = prefix;
break;
case 'altName':
label = `${prefix} ${altName?.length ? `(${altName})` : ''}`;
break;
case 'abbrev':
label = `${prefix} ${abbr?.length < 5 ? `(${abbr})` : ''}`;
break;
default:
label = `${prefix}`;
}
selectOptions.push({
value: tz.name,
label: label,
offset: tz.current.offset,
abbrev: abbr,
altName: altName,
});
return selectOptions;
}, [])
.sort((a, b) => a.offset - b.offset);
}
How can I get this to work?
Thank you so much in advance.
I'm simplifying quite a lot here, but it helps to understand. When you declare a function as async, what it does is wrap the function in a Promise. So, for example, this function :
async function something(){ return "hello world" }
can be read like :
function something(){
return new Promise((resolve, reject) => {
resolve("hello world")
})
}
In a nutshell, a Promise just schedules the execution of a function (in this case something) for later. So, we can only read the returned value later, when it's ready. When you call something(), it returns a Promise which is pending because it hasn't been executed yet (its execution is put on hold in a queue). You can learn more about how this works by reading about the event loop, the call stack and event queue.
To get the returned value of a Promise, we use a method called .then((value) => {}) which returns in the variable value the returned value of the function (in our case, value will contain "hello world"). So :
let r = something()
console.log(r) // Promise pending
r.then((value) => {
console.log(value) // "hello world"
})
If you want to use the value, you are gonna have to either :
Put your code inside the .then() and continue there
Put your code inside an async function and use await in front of the call
async function run(){
let value = await something()
console.log(value) // "hello world"
// do things with value
}
run()
This is a similar question that is already answered with some good explanation
Well basically async function returns a promise.
You can use use let somevariable = await okay() inside an async function
OR
You could do it like
okay().then((resp)=>{
console.log(resp)
})
An async function return a promise. Try that:
const okay = async () => {
return await getTimezoneLabel(timezone);
};
okay().then(result=>console.log(result));
or if you call okay() inside another async function you may use await syntax:
// should be inside async function
const result = await okay();

How to compare the value resulting from two promises in Javascript?

async function getDNShomeIP(){
var response = await fetch('https://dns.google/resolve?name=example.com'); // this uses the google api
var json = await response.json();
var homeIPadress = json.Answer[0].data;
console.log(homeIPadress);
return homeIPadress;
};
async function getCurrentIP(){
var response = await fetch("https://api.ipify.org?format=json");
var json = await response.json()
var currentIPadress = json.ip;
return currentIPadress;
}
var homeIPadress = getDNShomeIP();
var currentIPadress = getCurrentIP();
if (homeIPadress == currentIPadress){
alert("from same from lol");
} else {
alert("not from same")
};
Hi there,
I wanted to know how to compare the values of two promises in Javascript.
I can't work out how to make the program wait before the if statement.
The statement just evaluates to false if the promises are not yet fulfilled so program follows the else branch.
Thanks
Use the "await" keyword inside another "async" function so that the function waits for a response before it continues execution.
async function testEquality() {
var homeIPadress = await getDNShomeIP();
var currentIPadress = await getCurrentIP();
if (homeIPadress === currentIPadress) {
alert("from same from lol");
} else {
alert("not from same")
};
}
testEquality();
I would also recommend you use triple equal (===) to compare the results as this uses strict equality comparison.
You could wrap it in another async function:
async function execute() {
var homeIPadress = await getDNShomeIP();
var currentIPadress = await getCurrentIP();
if (homeIPadress == currentIPadress){
alert("from same from lol");
} else {
alert("not from same");
}
}
execute();
first you need to fix your fetch function, then fix the async await function
you have to put your await function on async function just like this,
fix your getdnshomeip just like the code below
function getCurrentIP(){
return fetch("https://api.ipify.org?format=json")
.then( r => r.json())
.then( r => r);
}
const check = async () => {
var currentIPadress = await getCurrentIP();
var homeIPadress = await getDNShomeIP();
if (homeIPadress === currentIPadress){
alert("from same from lol");
} else {
alert("not from same")
};
}
check();
You're describing a function I created
async function getDNShomeIP(){
var response = await fetch('https://dns.google/resolve?name=example.com');
var json = await response.json();
var homeIPadress = json.Answer[0].data;
console.log(homeIPadress);
return homeIPadress;
};
async function getCurrentIP(){
var response = await fetch("https://api.ipify.org?format=json");
var json = await response.json()
var currentIPadress = json.ip;
console.log(currentIPadress);
return currentIPadress;
}
const { eq } = rubico
eq(getDNShomeIP, getCurrentIP)().then(console.log)
<script src="https://unpkg.com/rubico/index.js"></script>
documentation for eq

Code won't execute in function containing return?

I've run into some issues with my scoping, I'm new to javascript so my apologies for my inexperience. The issue i'm having is I don't understand why my console.log within the function groupA(thename) curly braces won't allow code to output. In visual studio's it greys the code out. I think it may be due to the return fetch(`${url}${thename}`), because the code won't grey out when I remove that return. Why does the return function do this?
My goal is to correctly chain each function together so the data pushed into birds_array can be returned via the groupA function. How would I go about correctly formatting these functions to allow this to be possible?
const birds_array = []
let groupAname = "Old World sparrow"
groupA(groupAname);
function groupA(thename) {
return fetch(`${url}${thename}`)
.then(response => response.text())
.then(body => {
const $ = cheerio.load(body);
$('.llgymd').each( (index, element) => {
const $element = $(element);
const names = $element.text();
groupA_array[index] = names;
});
groupA_loop()
function groupA_loop(){
for(j = 0; j < groupA_array.length; j++){
if(!birds_array.includes(groupA_array[j])){
birds_array.push(groupA_array[j]);
}
// code functions here
console.log(birds_array);
}
// code functions here
console.log(birds_array);
}
// code functions here
console.log(birds_array);
});
// code does not function here
console.log(birds_array);
}
// Create a async function to await any async code. Else u get error.
async function main() {
let groupAname = "Old World sparrow";
// Await for the promise to be resolved. // Like pause call
const birds_array = await groupA(groupAname);
// Result done, print
console.log(birds_array)
}
main()
Sample:
const delayData = (num) => {
return new Promise((r) => {
setTimeout(() => {
r(num);
}, 1000);
});
};
async function main() {
const num = await delayData(1);
console.log(num); // 1
const num2 = await delayData(2);
console.log(num2); // 2
}
main();
// Using then
delayData(1).then(num => {
console.log(num) // 1
})
delayData(2).then(num => {
console.log(num) // 2
})

How can I access and use a return value from a do while loop?

I am trying to access return data from a do while loop, but I am unable to do so.
I have stored the information in a new variable (starships) and then returned this variable, but it says starships is not defined. I see that this may be a scoping issue, how can I resolve this?
async function getData() {
const allResults = [];
let url = 'https://swapi.co/api/starships/';
do {
const res = await fetch(url);
const data = await res.json();
url = data.next;
allResults.push(...data.results);
console.log(allResults);
} while (url !== null)
let starships = allResults;
return starships;
}
console.log(starships);
You need to get the value which is returned from getData. The most obvious way to do this with the async/await structure you have is to just await it:
async function getData() {
const allResults = [];
let url = 'https://swapi.co/api/starships/';
do {
const res = await fetch(url);
const data = await res.json();
url = data.next;
allResults.push(...data.results);
console.log(allResults);
} while (url !== null)
let starships = allResults;
return starships;
}
async function doTheDo() {
const test = await getData();
console.dir(test);
}
doTheDo();
you can do this. starships is defined inside the loop. Additionally, you are not calling getData() function. You can store that return value like this
const result = await getData();
console.log(result);
or you can directly print like this. console.log(await getData())
async function getData() {
const allResults = [];
let url = 'https://swapi.co/api/starships/';
do {
const res = await fetch(url);
const data = await res.json();
url = data.next;
allResults.push(...data.results);
console.log(allResults);
} while (url !== null)
return allResults;
}
console.log(await getData());
Async functions return a promise, which means you have to access the return value with a .then().
However, you have another problem: starships is in the scope of the function getData() which you have defined, but not called.
So first lets call your function:
async function getData() {
const allResults = [];
// do stuff
let starships = allResults;
return starships;
}
console.log(getData());
Now you will see that your log value is [object Promise] which isn't so helpful in its current form. This is because the code outside the async function is running synchronously, which means we don't have the value yet, just a promise to maybe return the value sometime in the future.
So now we need to access the promise asynchronously using the .then() like so:
async function getData() {
const allResults = [];
// do stuff
let starships = allResults;
return starships;
}
getData().then(starships => {
console.log(starships);
});
Now you should see the info you were expecting to be logged.
You can also save promise to a variable and pass it around and access it elsewhere in your code like so:
async function getData() {
const allResults = [];
// do stuff
let starships = allResults;
return starships;
}
let starshipPromise = getData();
// time & code passes...
starshipPromise.then(starship => {
console.log(starship);
}).catch(error => {
// handle error
});
And don't forget to catch your rejected promises!
See the MDN docs on Async functions: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
And if you need more info on promises, go here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Why does Promise.all with array filter result in an empty array?

I wrote a function to filter a time interval from an array.
The function seems to work and prints skip and accept were appropriate and prints no error.
However, it results in an empty array.
getDate() is a function which returns a date so it can be resolved to a time using getTime(). That works.
async function getInterval(climatedata,harvestdate,period) {
return new Promise(function(resolve, reject) {
getDate(harvestdate,-1*period).then((sval)=>{
let start = sval.getTime();
getDate(harvestdate,0).then(async(eval)=>{
let end = eval.getTime();
let filtered = await Promise.all(climatedata.filter((curVal,index,arr) => {
getDate(curVal[0]).then((tval)=>{
let td = tval.getTime();
//console.log(start,td,end);
if(td >= start && td <= end) {
console.log("accept"); //although this is printed for the expected subset, nothing is in the filtered array.
return true;
} else {
//console.log("skip");
return false;
}
}).catch((err)=>{console.log(err);});
}));
console.log("filtered",filtered); //here I would expect an array with some rows.
//console.log("bef",climatedata.length,"aft",filtered.length); //this is always bef 8000 aft 0
resolve(filtered);
});
});
});
}
I also tried a sligth variant using .then() on Promise.all but to no avail.
What am I doing wrong?
Thank you,
Jens
So, there's a few issues with your code.
First, your actual question. Note that filter returns a new array with elements that pass the test function. To pass the test function, any truthy value returned in that iteration of the function will mean that the item at that index in the array should pass. So, you have:
await Promise.all(climatedata.filter((curVal,index,arr) => {
getDate(curVal[0])...
};
Your first immediate problem is that you aren't returning anything in the filter's callback function, which means you are returning undefined in each iteration of the filter. undefined == false, so the test does not pass for that iteration. Since none of the tests pass, what you really end up with is:
await Promise.all([undefined, undefined, ...])
Which will indeed resolve to an array of undefined.
Now that we have that out of the way, lets clean up your code a whole bunch. First, since you are using async, you should almost never need to use new Promise. Marking the function as async implicitly wraps whatever it returns in a promise, meaning you don't need to.
// NOTE: I've removed your console.log statements to make it simpler to read
async function getInterval(climatedata,harvestdate,period) {
return getDate(harvestdate,-1*period).then((sval)=>{
let start = sval.getTime();
getDate(harvestdate,0).then(async(eval)=>{
let end = eval.getTime();
let filtered = await Promise.all(climatedata.filter((curVal,index,arr) => {
return getDate(curVal[0]).then((tval)=>{ // NOTICE: I added `return` here to beging to fix your filter problem
let td = tval.getTime();
if(td >= start && td <= end) {
return true;
} else {
return false;
}
}).catch((err)=>{console.log(err);});
}));
return filtered;
});
});
}
Ok, next, since you're in async world, you never need to use .then or .catch:
async function getInterval(climatedata, harvestdate, period) {
let sval;
try {
sval = await getDate(harvestdate, -1 * period);
} catch (error) {
console.log('getting `sval` failed, oh no!');
throw error;
}
let start = sval.getTime();
let eval;
try {
eval = await getDate(harvestdate, 0);
} catch (error) {
console.log('getting `eval` failed, oh no!');
throw error;
}
let end = eval.getTime();
let filtered = await Promise.all(climatedata.filter(async (curVal,index,arr) => {
let tval;
try {
tval = getDate(curVal[0]);
} catch (error) {
console.log('getting `tval` failed, oh no!');
throw error;
}
let td = tval.getTime();
if(td >= start && td <= end) {
return true;
} else {
return false;
}
}));
return filtered;
}
So much nicer. But ok, let's get to the meat of your issue again: you want to filter a list of promises down. That means you can't only use filter, you need to use filter and map:
async function getInterval(climatedata, harvestdate, period) {
let sval;
try {
sval = await getDate(harvestdate, -1 * period);
} catch (error) {
console.log('getting `sval` failed, oh no!');
throw error;
}
let start = sval.getTime();
let eval;
try {
eval = await getDate(harvestdate, 0);
} catch (error) {
console.log('getting `eval` failed, oh no!');
throw error;
}
let end = eval.getTime();
const filterTest = (curVal, index, arr)
const climatedataPromises = climatedata.map(curVal => getDate(curVal[0])); // Create a list of promises
const climatedata = await Promise.all(climatedataPromises); // Wait for them all to return
return climatedata.filter((tval, index) => { // Now run your filter
let td = tval.getTime();
if(td >= start && td <= end) {
return true;
} else {
return false;
}
});
}
Enjoy :)
*I don't promise that I'm not missing a closing paren or bracket in there somewhere :)

Categories

Resources