
Understanding Asynchronous JavaScript 👨💻
Asynchronicity
Asynchronicity is the backbone of modern web development in JavaScript
JavaScript is single threaded (one command executing at a time) and has a synchronous execution model (each line is executed in order the code appears).
So what if we need to wait some time before we can execute certain bits of code? We need to wait on fresh data from an API/server request or for a timer to complete and then execute our code We have a conundrum - a tension between wanting to delay some code execution but not wanting to block the thread from any further code running while we wait.
Let’s see two examples: In what order will our console logs occur?
function printHello(){ console.log(“Hello”); } setTimeout(printHello,1000); console.log(“Me first!”);
The output:
'Me first!' 'Hello'
function printHello(){ console.log(“Hello”); } setTimeout(printHello,0); console.log(“Me first!”);
The output:
'Me first!' 'Hello'
To understand the above behavior, we need to introduce 3 new components of our platform
- Web Browser APIs/Node background threads
- Callback/Message queue
- Event loop
Now we are interacting with a world outside of JavaScript:
We need a way of predictably understanding how this outside world will interact with our JavaScript execution model. What would happen here?
function printHello(){ console.log(“Hello”); } function blockFor1Sec(){ /*blocks in the JavaScript thread for 1 second*/ } setTimeout(printHello,0); blockFor1Sec() console.log(“Me first!”);
Promises
Essentially, a promise is a returned object to which you attach callbacks, instead of passing callbacks into a function.
Promises - the readability enhancer:
- Special objects built into JavaScript that get returned immediately when we make a call to a web browser API/feature (e.g. fetch) that’s set up to return promises (not all are)
- Promises act as a placeholder for the data we hope to get back from the web browser feature’s background work
- We also attach the functionality we want to defer running until that background work is done (using the built in .then method) — Promise objects will automatically trigger that functionality to run
- The value returned from the web browser feature’s work (e.g. the returned data from the server using fetch) will be that function’s input/argument
Using two-pronged ‘facade’ functions that both initiate background web browser work and return a placeholder object (promise) immediately in JavaScript
function display(data) { console.log(data) } const futureData = fetch('https://twitter.com/will/tweets/1') futureData.then(display); console.log('Me first!');
In the above code, the function display will be declared and its function text and name will be stored in the global memory. futureData
will be uninitialized until fetch is executed (futureData
will be the returned value of fetch ). fetch()
is a two-pronged 'facade' function, it's a function masking a bunch of JS functionality and browser work. On one hand, it's sending an XMLHttpRequest
to Twitter's API (browser work), on the other hand, it's returning us a Promise object (JS work).
We're hoping it will return the data from Twitter. Just like setTimeout
kicks off Timer in the browser, fetch kicks off XHR
(XMLHttpRequest
) object. fetch will immediately return an object with a property on it called value, which is undefined (the data received from Twitter will be set to value). It also has a property called onFulfillment
which is an empty array; we can store any functions we want to auto-trigger when the value
gets updated to the data. This returned object will be set to FutureData
. You might say that we can run FutureData.value
, but the problem is that we don't know when the value will be updated (right now it's undefined
). (On completion of the request in future, we will assign the received data to the value, which, like we said earlier, will trigger all the functions in onFulfillment
.
The next line seems that it's calling display function. All .then()
does is it takes its functions and stores it in onFulfillment
array; the functions are triggered when the value is updated. So here, when we will assign the received data to the value, .then()
will store the display
function (its argument) ). Next, we run console.log('Me first!');
. Now, the response data comes, the status
property is set to resolved
and the value is updated to hi
. The display
function will be triggered with value
as its argument.
Discussion (8 comments)