bongbang bongbang - 2 months ago 11
Javascript Question

Execute code that deferred function depends on while waiting

In the minimal example below, the replacement of old content is deferred by

setTimeout
to give the user time to finish viewing it, but new content is being prepared in the meantime so as to be efficient in this potentially expensive task.



var div = document.getElementById('wrapper');
var newContent = document.createElement('ul');

setTimeout(function() {
var header = div.firstElementChild;
header.innerHTML = 'New Content';
header.nextElementSibling.remove();
div.appendChild(newContent);
}, 2000);

// Make new content while we wait
[1, 10, 100, 1000].forEach(function(x) {
var li = document.createElement('li');
li.innerHTML = 'Factorial of ' + x + ' is ' + factorial(x);
newContent.appendChild(li);
});

function factorial(num) {
if (num === 0) {
return 1;
} else {
return (num * factorial(num - 1));
}
}

<div id='wrapper'>
<h1>Old content</h1>
<p>Read it before it's gone.</p>
</div>





My questions are:


  1. Is this an advisable thing to do? I welcome "Why do you want to do this?" responses, but please give a reason not to do it and/or suggest an alternative.

  2. If it is, then do I need to worry about
    newContent
    not being ready when the replacement is due to take place?



PS I'm using jQuery, so please feel free to suggest it as a solution.

mab mab
Answer

You have two requirements:

  1. Do not hide the introduction until at least 2 seconds have passed.
  2. Do not hide the introduction until the content is ready.

The changes below satisfy that.

<html>
<body>
<div id='wrapper'>
  <h1>Old content</h1>
  <p>Read it before it's gone.</p>
</div>
<script>
var div = document.getElementById('wrapper');
var newContent = document.createElement('ul');
var contentReady = false;
var timesUp = false;

function onContentReady() {
  if (! timesUp || ! contentReady) return;
  var header = div.firstElementChild;
  header.innerHTML = 'New Content';
  header.nextElementSibling.remove();
  div.appendChild(newContent);
}

setTimeout(function() { 
    timesUp = true;
    onContentReady();
  } , 2000);

function makeContent() {
    // Make new content while we wait
    [1, 10, 100, 1000].forEach(function(x) {
      var li = document.createElement('li');
      li.innerHTML = 'Factorial of ' + x + ' is ' + factorial(x);
      newContent.appendChild(li);
    });
    contentReady = true;
    onContentReady();
}

function factorial(num) {
  if (num === 0) {
    return 1;
  } else {
    return (num * factorial(num - 1));
  }
}

setTimeout(function() { 
    makeContent();
  } , 4000);
</script>
</body>
</html>

Change the time value in this code to be less than 2 seconds and more than two seconds to see that.

setTimeout(function() { 
    makeContent();
  } , 4000);