Repository navigation
Asynchrony
To do all their work efficiently, browsers use an asynchronous execution model. That's a fancy way of saying "they do little bits of lots of tasks until the tasks are done."
let sum = 1 + 1; // Line 1
let lis = document.querySelectorAll("li"); // Line 2In this case, when we hit the definition of sum, this work doesn't rely on
any "questionable" or "unknowably long" process. As soon as the work of Line 1 is done, JavaScript will then go to work finding elements and assigning them
to lis in Line 2.
But let's consider a "blocking" operation. Imagine we had a synchronous function
called synchronousFetch("URL STRING") that fetches data from the network.
let tooMuchData = synchronousFetch("http://genome.example.com/..."); // Line 1
let lis = document.querySelectorAll("li"); // Line 2
console.log(tooMuchData);That work in Line 1 could take a long time (e.g. slow network), or might fail (e.g. failed login), or might retrieve a huge amount of data (e.g. The Human Genome).
It's possible that the let lis in Line 2 will never execute! While
JavaScript is executing synchronousFetch it will not be able to animate gifs,
you won't be able to open a new tab, it will stop streaming SoundCoud, it will
appear "locked up." Recall our chef metaphor: while the chef prepares the bread,
the mashed potatoes grow cold and the boiled turkey congeals. Gross.
Asynchronous code in JavaScript looks a lot like event handlers. And if we think about it, that makes sense. You tell JavaScript:
Hey, do this thing. And then go do whatever maintenance you need: animate that gif, play some audio from SoundCloud, whatever. But when that first thing has an "I'm done" event, go back to it and do some work that I defined in a function when I called it.
asynchronousFetch("http://genome.example.com/...", tonOfGeneticData => sequenceClone(tonOfGeneticData)); // Line 1
let lis = document.querySelectorAll("li"); // Line 2In this case, JavaScript starts the asynchronousFetch in Line 1, and then
sets lis in Line 2. Some time later (who knows how long?), the fetch of data
finishes and that data is passed into the "callback" function as
tonOfGeneticData — back on Line 1.
Most asynchronous functions in JavaScript have this quality of "being passed a callback function." It's a helpful tool for spotting asynchronous code "in the wild."
JavaScript in the browser has an asynchronous execution model. This fact has little impact when you're writing simple code, but when you start doing work that might block the browser you'll need to leverage asynchronous functions.
While working asynchronously can be a bit of a headache for developers, it allows JavaScript to do other work whenever it has opportunity.
The easiest asynchronous wrapper function is window.setTimeout(). It takes as arguments:
setTimeout(() => console.log('Hello World!'), 2000)
console.log("No, me first")
Sure enough:
No, me first
Hello World!Since this code is in an asynchronous container, JavaScript can do other work and come back when the work "on the back-burner is done." If JavaScript didn't have an asynchronous model, while you waited those 2 seconds, no gifs would animate, streaming audio might stall. Asynchronous execution makes browsers the exceedingly useful tools they are.
JavaScript is so committed to trying to squeeze in work when it gets a chance that this has the exact same output!
setTimeout(() => console.log('Hello World!'), 0) // 0 Milliseconds!!
console.log("No, me first")