Home > database >  Run function again only after it has been completed
Run function again only after it has been completed

Time:10-30

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:

  1. 5 second delay between "Hello" and the first "Morning".
  2. 5 second delay between each "Morning".
  3. 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>

  • Related