1

I'm developping a local (no server, no ajax) piece of code that does "heavy" computing and visual representations. My ever growing problem is thus : pieces of code will constantly be executed before preceding lines of code have finished! This is killing me and I've read, read and read about callbacks, promises, but unless I'm thick headed it doesn't seem to apply to my context and I can't wrap my head around how Javascript's flow of execution works.

If I call 3 functions from within a .js file loaded in the head of my html file like thus :

FirstFunction(lenghtOfDataset); // creates a complex array of arrays of objects (about 10,000 elements)
SecondFunction (Dataset); // renders a D3.js svg visualization based on the dataset (about 1,000 elements)
ThirdFunction (Dataset); // creates an html table by using jQuery .append (bad, I know) using the same dataset (around 10,000 elements)

Now, why, oh why does code in the third function is executed before the first function has even finished executing? (Of course, resulting in an "undefined" error)

Another example which drives me crazy goes like this :

$("#my-table").append("<thead><tr>");
for (i=FirstNumber; i<=LastNumber; i++) { // about 1000 elements
    $("#my-table").append("<th>" + i + "</th>");
    }   
$("#my-table").append("</tr></thead>");

Again, why, oh why does the closing "</tr></thead>" get inserted before the for loop is even finished?!

EDIT : OK this example has invalid code, thanks to mplungjan for providing a solution, but this is not the main issue. Consider this code then :

$("#working-overlay").css("display", "block");
for (var i = 1; i <= 10000; i++) {              
        Number[i] = {};
        Number[i].value = i;
        Number[i].divisors = DivisorsOf(i); // I have a function that calculates divisors   
        Number[i].factors = FactorsOf(i); //// I have a function that calculates factors
}
$("#working-overlay").css("display", "none");

The working-overlay will get display:none before computation is finished. How to go about not behaving that way? I don't really care about the overlay here, it's an example, but I do care that the next computation in line will refer to an undefined value because the for loop isn't really finished when the next line of code is executed.


Please note that I'm not looking for a copy-and-paste solution nor a workaround in the setTimeout style (works inconsistently, anyway), but I want to understand why it behaves like so: why does Javascript code execution flows, weirdly, ahead of itself?

21
  • This isn't about Javascript; it's about jQuery. jQuery follows a functional design pattern, and executes things asynchronously. It shouldn't matter, nor should you care, in what order it executes things. You'd better get used to it, because asynchrony is at the hear of the way all browsers work. Commented Oct 19, 2016 at 14:54
  • @RobertHarvey I just accidentally deleted my comment. The link I had referenced earlier that I believe you may get some additional information out of is here: Synchronous vs Asynchronous. Commented Oct 19, 2016 at 14:55
  • @RobertHarvey well well, there is a time where order matters, if not, programming would have been impossible, even in functional style. Commented Oct 19, 2016 at 14:56
  • 1
    You cannot append partial html in jQuery. What you see is jQuery trying to FIX your illegal HTML - here is how you could do it correctly: jsfiddle.net/mplungjan/k4xzo3yu Commented Oct 19, 2016 at 15:03
  • 1
    It is not. His code is invalid Commented Oct 19, 2016 at 15:11

1 Answer 1

1

Your first example is likely an issue of asynchronous handling js D3.js as we mentioned in our comments

Your second example is invalid. You cannot use append to insert partial HTML

Here is a valid way:

var $tHead = $("#myHead"),
  $headerRow = $("<tr/>");
for (var i = 0; i <= 1000; i++) { // about 1000 elements
  $headerRow.append("<th>" + i + "</th>");
}
$tHead.append($headerRow);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<table id="my-table">
  <thead id="myHead"></thead>
</table>

Likely faster way

var $tHead = $("#myHead"),
  headerRow = "<tr>";
for (var i = 0; i <= 1000; i++) { // about 1000 elements
  headerRow+="<th>" + i + "</th>";
}
headerRow+="</tr>";
$tHead.append(headerRow);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<table id="my-table">
  <thead id="myHead"></thead>
</table>

Sign up to request clarification or add additional context in comments.

14 Comments

Thank you for correcting my invalid code! It will be useful for sure, but that still doesn't answer my existential question.
The d3 is likely using Async execution - see posted link to other answer - JS is single threaded unless execution is deferred in async callbacks
So if I understand this right D3 and jQuery use async execution, so I would have to somehow write Javascript without using any libraries/tools in order for my code to be sync execution? Sounds like a nightmare ;)
No you do not. You need to understand where they are using it. The append you did was not async. It just had a side effect of closing your tr before appending - you need to show us your code and we can help you execute the functions in the correct place.
Interesting, thanx. Screen buffer and browser. That explains why I consistently need to put a setTimeout(function Heavy_Calculations,300) after showing a "waiting overlay" otherwise the overlay doesn't have time to show. But it still doesn't explain why a var MyVar = 345 in the first function still don't get through before the third function executes (the example in my question). I'll try to setup a fiddle of this behavior.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.