I'm trying to make a program that adds text to a web-page, like so:
Hello
Morning
Morning
Morning
Morning
Evening
There should be:
- 5 second delay between "Hello" and the first "Morning".
- 5 second delay between each "Morning".
- 6 second delay between the last "Morning" and "Evening".
Here's the whole HTML and JavaScript I've got so far.
function notify(msg, loops, taskTime) {
var ul = document.getElementById("notifications");
for (let i = 0; i < loops; i ) {
(function(i) {
window.setTimeout(function() {
var li = document.createElement("li")
li.appendChild(document.createTextNode(`${msg}`));
ul.appendChild(li)
}, taskTime * i)
}(i))
}
}
notify('Hello', 1, 5000)
notify('Morning', 4, 5000)
notify('Evening', 1, 6000)
<div>
<ul id="notifications" style="list-style-type:none;margin-left:10%;"></ul>
</div>
My problem is that on loading the web-page, the output is:
Hello
Morning
Evening
Morning
Morning
Morning
How can I make sure that the function is ran in the order I want it to and not this mixed output? The first 3 outputs also appear instantly instead of a delay. How do I avoid that?
CodePudding user response:
Multiply the number of miliseconds so the setTimeout that comes after has the correct time assigned. Also, you was multiplying the taskTime
and i
, which was always 0. I replaced i
with i 1
instead.
Just try this JavaScript code instead (it works):
function notify(msg, loops, taskTime) {
var ul = document.getElementById("notifications");
for (let i = 0; i < loops; i ) {
(function (i) {
window.setTimeout(function () {
var li = document.createElement("li")
li.appendChild(document.createTextNode(`${msg}`));
ul.appendChild(li)
}, taskTime * (i 1))
}(i))
}
}
notify('Hello', 1, 5000)
notify('Morning', 4, 5000 * 2)
notify('Evening', 1, 6000 5000 * 6)
CodePudding user response:
Based on Mike's comment:
tasks = [
{message: 'Hello', delay: 5000},
{message: 'Morning', delay: 5000},
{message: 'Morning', delay: 5000},
{message: 'Morning', delay: 5000},
{message: 'Morning', delay: 5000},
{message: 'Evening', delay: 6000},
]
function runTask(index) {
var ul = document.getElementById("notifications");
var li = document.createElement("li");
li.appendChild(document.createTextNode(`${tasks[index].message}`));
ul.appendChild(li);
if(index < tasks.length - 1){
setTimeout( () => runTask(index 1), tasks[index].delay);
}
}
if(tasks.length > 0) runTask(0); //make sure the task list has at least one element.
CodePudding user response:
In modern JavaScript, async
functions should probably be your first port of call when writing async code. They are clearer and usually easier to understand.
In the following, delay
promisifies setTimeout
.
notify
adds li
elements to the document in a loop, with a delay added at the beginning of each iteration.
I am unsure if this behaves as you need for the first "Hello"
.
const delay = (ms) => new Promise((res) => setTimeout(res, ms))
const ul = document.getElementById("notifications")
async function notify(msg, count, ms) {
for (let i = 0; i < count; i ) {
await delay(ms)
const li = document.createElement('li')
li.innerText = `${msg} ${Date()}`
ul.appendChild(li)
}
}
(async () => {
await notify('Hello', 1, 5000)
await notify('Morning', 4, 5000)
await notify('Evening', 1, 6000)
})()
<p>Notifications will appear below:</p>
<ul id="notifications"></ul>