how can I edit the same message multiple times with a delay...?
Here is what i tried... :
message.channel.send(`a`)
.then(message => {
setTimeout( () => {
message.edit(`ab`)
},1000);
})
.then(message => {
setTimeout( () => {
message.edit(`abc`)
},1000);
})
.then(message => {
setTimeout( () => {
message.edit(`abcd`)
},1000);
})
.then(message => {
setTimeout( () => {
message.edit(`abcde`)
},1000);
});
smth like this should work, but if i try this one the error is: of course Cannot read property 'edit' of undefined (the error is at the "message.edit (abc)" part.)
The problem is that there is nothing is passed into the second .then
The value passed to the next .then is always the return value of the previous .then
For example:
Promise.resolve('foo').then(value => {
console.log(value)
return 'abc'
}).then(console.log)
will fist log foo and then abc
The easiest solution I can think of is to increase the setTimeout delay by 1000 each time
message.channel.send('a').then(message => {
setTimeout(() => message.edit('ab'), 1000)
setTimeout(() => message.edit('abc'), 2000)
setTimeout(() => message.edit('abcd'), 3000)
setTimeout(() => message.edit('abcde'), 4000)
})
If you wanted this to be more general you could do something like this:
function changeMessage(delay, messages, message) {
for(i in messages) {
setTimeout(() => message.edit(messages[i]), delay * i)
}
}
message.channel.send('a').then(message => changeMessage(1000, ['ab', 'abc', 'abcd', 'abcde'], message))
The function changeMessage takes in a delay time, an array of messages, and the actual message object you want to edit, and just edits the message to each new string in the array of messages every x seconds
This problem has a nice syntactic solution, but oftentimes it's easier to use async/await if you want to run a bunch of Promises sequentially
Related
Hey guys i keep getting undefined, do i need to somehow create a promise or there is another way around, my value only exist inside a then() , also i am calling same thing twice is there a nice way of writing this together.
it.only('should switch to transaction history second page', () => {
let firstRowDate;
let secondRowDate;
TransactionsPage.tableRows.eq(0).find("td.cdk-cell.date.cdk-column-Date.table-cell").then((value) =>{
firstRowDate = value.text()
})
console.log(firstRowDate) -> undefined
TransactionsPage.appIconNext.click();
TransactionsPage.tableRows.eq(0).find("td.cdk-cell.date.cdk-column-Date.table-cell").then((value) =>{
secondRowDate = value.text()
})
console.log(secondRowDate) -> undefined
cy.url().should('eq', `${Cypress.config().baseUrl}/${Route.TransactionListPage + '?page=2'}`);
})
});
You have to write the console.log inside a then to make sure cypress executes the command synchronously
TransactionsPage.tableRows
.eq(0)
.find('td.cdk-cell.date.cdk-column-Date.table-cell')
.then((value) => {
secondRowDate = value.text()
})
.then(() => {
console.log(secondRowDate)
})
You can use aliases to save values and use them like this:
TransactionsPage.tableRows
.eq(0)
.find('td.cdk-cell.date.cdk-column-Date.table-cell')
.then((value) => {
cy.wrap(value.text()).as('value')
})
cy.get('#value').then((value) => {
//Access value here
})
You can do something like this:
it.only('should switch to transaction history second page', () => {
TransactionsPage.tableRows
.eq(0)
.find('td.cdk-cell.date.cdk-column-Date.table-cell')
.then((value) => {
cy.wrap(value.text()).as('value1')
})
TransactionsPage.appIconNext.click()
TransactionsPage.tableRows
.eq(0)
.find('td.cdk-cell.date.cdk-column-Date.table-cell')
.then((value) => {
cy.wrap(value.text()).as('value2')
})
//compare values
cy.get('#value1').then((value1) => {
cy.get('#value2').then((value2) => {
expect(value1).to.eq(value2)
})
})
cy.url().should(
'eq',
`${Cypress.config().baseUrl}/${Route.TransactionListPage + '?page=2'}`
)
})
You can console log it in the same .then().
TransactionsPage.tableRows.eq(0).find("td.cdk-cell.date.cdk-column-Date.table-cell").then((value) =>{
secondRowDate = value.text()
console.log(secondRowDate)
})
I'm trying to learn exactly how to oversee the order in which my script runs using asynchronous functions and promises. At this point I've read/watched many information resources to try to get this right but something about my code just isn't working:
I have a generic vue.js object containing my methods, and running the series of functions asynchronously when the app is mounted:
var testAPP = new Vue({
el: '#test-app',
data: {
},
methods: {
fake_fetch: function () {
return new Promise((resolve) => {
setTimeout(() => {console.log("Returning fetch results."); resolve("good boy!")}, 10000)
})
},
first_step: function () {
console.log('Playing with my puppy!')
this.fake_fetch()
.then((data) => {
let praise = "Buddy is a " + data
console.log(praise)
return ("nap.")
})
.then((data) => {
return new Promise((resolve) => {
setTimeout(() => {console.log("Phew! We are taking a " + data); resolve(true)}, 20000)
})
})
},
second_step: function () {
console.log('Baking some cookies!')
this.fake_fetch()
.then((data) => {
data = data.replace(" ", ", ")
let praise = "Oh man these are " + data
console.log(praise)
return ("nap.")
})
.then((data) => {
return new Promise((resolve) => {
setTimeout(() => {console.log("I'm so full, I'm taking a " + data); resolve(true)}, 20000)
})
})
},
third_step: function () {
console.log('Putting out a hit on Polly')
this.fake_fetch()
.then((data) => {
let praise = "The job was a success? You did " + data
console.log(praise)
return ("nap.")
})
.then((data) => {
return new Promise((resolve) => {
setTimeout(() => {console.log("A moment of silence for Polly as he takes a dirt " + data); resolve(true)}, 20000)
})
})
},
get_started: function () {
v = this
async function my_day(v) {
const task_one = await v.first_step()
const task_two = await v.second_step()
const task_three = await v.third_step()
return ([task_one, task_two, task_three])
}
my_day(v).then((data) => {
if (false in data) {
return ("Something went wrong.")
} else {
return ("My day is done, time to rest... again.")
}
})
},
},
mounted: function () {
this.get_started()
}
})
The result I expect to get based on the order I 'thought' would be correct is this:
Playing with my puppy!
Returning fetch results.
Buddy is a good boy!
Phew! We are taking a nap.
Baking some cookies!
Returning fetch results.
Oh man these are good, boy!
I'm so full, I'm taking a nap.
Putting out a hit on Polly
Returning fetch results.
The job was a success? You did good boy!
A moment of silence for Polly as he takes a dirt nap.
My day is done, time to rest... again.
Ignoring the silliness of the output statements, thats the order they should appear. My current code gives me this:
Playing with my puppy!
Baking some cookies!
Putting out a hit on Polly
My day is done, time to rest... again.
Returning fetch results.
Buddy is a good boy!
Returning fetch results.
Oh man these are good, boy!
Returning fetch results.
The job was a success? You did good boy!
Phew! We are taking a nap.
I'm so full, I'm taking a nap.
A moment of silence for Polly as he takes a dirt nap.
The first four lines come up right away which doesn't feel right as there should be my built in delays stalling each 'step' function before the next one fires.
I've tried many things from making 'my_day()' its own function within methods and calling it via this.my_day() but that didn't make a difference. I've tried playing around with different return statements on the promises as well as making each following step function dependent on the variable of its predecessor but these resulted in the same functionality.
Why are my functions starting at the same time and not following the 'order' I have built into my async function?
Thank you for any help!
Also the html I used to run this in Edge is simple, I was just interested in the console:
<!DOCTYPE html>
<script src="https://unpkg.com/vue#2.6.10/dist/vue.min.js"></script>
<script type="text/javascript" src="C:\Users\adarwoo\Documents\Python Scripts\JS\async2.js"></script>
You are using await, but there is no async
first_step: async function() { // <-- async needed
console.log('Playing with my puppy!')
return this.fake_fetch() // <-- return needed
.then((data) => {
let praise = "Buddy is a " + data
console.log(praise)
return ("nap.")
})
.then((data) => {
return new Promise((resolve) => {
setTimeout(() => {
console.log("Phew! We are taking a " + data);
resolve(true)
}, 20000)
})
})
}
I'm practicing with some Promises and closures. I have a forEach loop where I return a Promise with a 3 second timeout and after the Promise resolves, it should log a statement.
I think I'm doing this incorrectly because I'm expecting every 3 seconds to see a log of "111" followed by "222" however I am seeing a delay of 3 seconds then immediately 3 logs of "111" "222".
let arr = [1,2,3];
arr.forEach((x,i) => {
(function() {
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log("111")
resolve(true)
}, 3000);
})
})()
.then(() => {console.log("222")})
});
You simply forgot to tell javascript to "await" for that timeout between each iteration of the for loop. So what's happening it that javascript will run the for loop, schedule three timeouts while doing so, then those three timeouts all go off at once.
If you add an await like so, then it'll work as you expected.
(async function() {
let arr = [1, 2, 3];
for (let x of arr) {
await (function() { // <-- await added
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("111")
resolve(true)
}, 3000);
})
})()
.then(() => {
console.log("222")
})
}
})()
I switched to for-of, because .forEach() doesn't work with async functions. I also wrapped the whole thing inside an async IIFE because a top-level await wasn't allowed there - depending on where you put this code, you might not have to wrap it inside an async IIFE.
EDIT
Just realized, you didn't use async/await stuff anywhere in your original question. I don't know if you've learned about it yet but you don't have to know it to solve this particular problem.
Here's another way to do it without async/await.
let arr = [1, 2, 3];
let promise = Promise.resolve();
arr.forEach((x,i) => {
promise = promise
.then(function() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("111")
resolve(true)
}, 3000);
})
})
.then(() => {
console.log("222")
})
});
This is basically building a promise chain inside the loop. If you "unwound" the loop, it would look like this:
promise = Promise.resolve()
promise = promise
.then(() => /* wait 3000 ms and log "111" */)
.then(() => { console.log("222") })
.then(() => /* wait 3000 ms and log "111" */)
.then(() => { console.log("222") })
.then(() => /* wait 3000 ms and log "111" */)
.then(() => { console.log("222") })
Because we're keeping around the a reference to the last promise, and we keep tacking onto the end of it, each new thing we tack on will happen after the last thing gets completed.
require("./getSongFromSpotify")().then(a => {
require("./instify")(a.artist,a.name).then(r => {
if (r.status === "ok"){
console.log("saved")
}else{
console.log("Instagram API have a problem!")
}
}).catch((r) => {console.error(r)})
}).catch((r) => {console.error(r)})
I need to execute this code in an infinite loop with 2000ms delay. How can I do this?
First of all, stop requiring modules for the each execution. Let's declare those separately, this will also make the code more clear and readable:
const getSong = require('./getSongFrompotify');
const instify = require('./instify');
Now let's write a function which we will call recursively after two seconds passed from the previous execution finish and the promisified timer:
function waitFor(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
})
}
function doJob() {
return getSong()
.then(song => instify(song.artist, song.name))
.then(result => {
if (result.status === 'ok') {
console.log('saved');
} else {
console.log('Problem!');
}
}) // no need to have 2 separate 'catch'
.catch(err => console.error(err)) // all errors fall here
.finally(() => waitFor(2000)) // anyway wait 2 seconds
.then(() => doJob()); // and run all again
}
Now, we simply need to call it:
doJob();
Note, that this approach will result in endless loop (as you asked for), but I think you'll probably need to setup some additional variable/flag which will be checked before of each iteration in order to be able stop it.
With async await syntax, this can be made to look quite straightforward:
const getSongFromSpotify = require("./getSongFromSpotify");
const instify = require("./instify");
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
async function keepPolling() {
while (true) { // forever (or until rejection)
let song = await getSongFromSpotify();
let result = await instify(song.artist, song.name);
if (result.status === "ok") {
console.log("saved");
} else {
console.log("Instagram API has a problem!");
}
await delay(2000);
}
}
keepPolling().catch(console.error);
I've been struggling to clear an Interval. It is inside a function that I call on a forEach statement for multiple objects.
The clearInterval is called inside a catch() for a promise. When it fails the console.log() works but not the clearInterval.
The code is as follows:
const myfunction = (object) => {
console.log(`Starting Interval for ${object.name}...`)
var timerLoop = setInterval( () => {
console.log(`Interval for ${object.name}`)
doSomething(object)
.then((result) => {
console.log(result)
doTheThing(result)
})
.catch( (err) => {
console.log('There was an error')
clearInterval(timerLoop)
console.error(err)
})
}, 1000)
}
According to this question and it's answer, I should be able to call clearInterval() from inside the actual interval, but I don't seem to get what is wrong with it.
What am I missing?