Luciano Mammino (@loige)
June 24, 2020
University Webinar Series
Principal Software Engineer at FabFitFun
👨🏻🏫 Mentor and co-organizer at NodeSchool Dublin
JavaScript is an high-level, interpreted, multi-paradigm, dynamic & loosely-typed programming language
High-level: the language abstracts many system details (e.g. memory management).
Focus on productivity rather than control.
int *array = malloc(10 * sizeof(int));
if (array == NULL) {
fprintf(stderr, "malloc failed\n");
return -1;
}
// ...
free(array);
var arr = []
C (low-level)
JavaScript (high-level)
Interpreted: the source code can be executed directly using an interpreter (there is no compilation step).
Focus on portability and productivity rather than performance
javac HelloWorld.java
java HelloWorld.class
node hello-world.js
Java (compile)
JavaScript (intepreted)
Multi-paradigm: the language supports multiple programming paradigms:
Focus on flexibility and freedom rather than consistency
dynamic: the type of variables does not need to be defined.
loosely typed: the type of variables can change over time and different types of variables can be combined (through auto-casting)
Focus on productivity rather than safety.
a = "Hello"
a = 2
b = "Hello" + 2 # TypeError!
var a = "Hello"
a = 2
var b = 'Hello' + 2 // 'Hello2'
python (dynamic, strongly typed)
JavaScript (dynamic, loosely typed)
Brendan Eich
(in a suit!)
In the last two decades, JavaScript has effectively revolutionized the web, eventually becoming the standard "de facto" for building dynamic websites and web applications!
Async I/O
In JavaScript, input/output operations (e.g. making an HTTP request) are non-blocking.
Most languages have blocking I/O by default
Let's make an HTTP request in Java
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://google.com")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
System.out.println("Request completed");
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://google.com")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
System.out.println("Request completed");
.
Output
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://google.com")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
System.out.println("Request completed");
.
Output
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://google.com")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
System.out.println("Request completed");
.
Output
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://google.com")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
System.out.println("Request completed");
.
Output
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://google.com")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
System.out.println("Request completed");
.
Output
(Blocking I/O)
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://google.com")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
System.out.println("Request completed");
<google home page HTML code>
Output
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://google.com")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
System.out.println("Request completed");
<google home page HTML code>
Request completed
Output
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://google.com")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
System.out.println("Request completed");
<google home page HTML code>
Request completed
Output
Code executed
"in order"
Is blocking I/O bad?
Is blocking I/O bad?
(it depends...)
Is your application I/O heavy?
Is your application I/O heavy?
If yes, then blocking I/O might not be optimal!
If you have to do 3 requests...
If you have to do 3 requests...
Req 1
time
If you have to do 3 requests...
Req 1
time
If you have to do 3 requests...
Req 1
time
Req 2
If you have to do 3 requests...
Req 1
time
Req 2
If you have to do 3 requests...
Req 1
time
Req 2
Req 3
If you have to do 3 requests...
Req 1
time
Req 2
Req 3
You can always use threads...
thread 1
time
thread 2
thread 3
You can always use threads...
thread 1
time
thread 2
thread 3
You can always use threads...
thread 1
time
thread 2
thread 3
But threads are...
You can always use threads...
thread 1
time
thread 2
thread 3
But threads are...
Complicated
You can always use threads...
thread 1
time
thread 2
thread 3
But threads are...
Complicated
Expensive
You can always use threads...
thread 1
time
thread 2
thread 3
But threads are...
Complicated
Expensive
Still a lot of idle time per thread!
You can always use threads...
thread 1
time
thread 2
thread 3
idle time
idle time
idle time
But threads are...
Complicated
Expensive
Still a lot of idle time per thread!
Let's understand JavaScript async I/O with a similar example...
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
.
Output
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
.
Output
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
.
Output
request "in the background"
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
Request completed (?)
Output
request "in the background"
not blocking,
execution continues...
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
Request completed (?)
Output
request "in the background"
not really completed, still in progress!
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
Request completed (?)
Output
request completed ⏰
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
Request completed (?)
Output
request completed ⏰
Callback function
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
Request completed (?)
<google home page HTML code>
Output
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
Request completed (?)
<google home page HTML code>
Output
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
Request completed (?)
<google home page HTML code>
Output
⚠️ Code NOT executed "in order"
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
Request completed (?)
<google home page HTML code>
Output
⚠️ Code NOT executed "in order"
①
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
Request completed (?)
<google home page HTML code>
Output
⚠️ Code NOT executed "in order"
①
②
request.get('https://google.com').end(
(err, resp) => {
console.log(resp.text)
}
)
console.log('Request completed (?)')
Request completed (?)
<google home page HTML code>
Output
⚠️ Code NOT executed "in order"
①
②
③
When is this approach convenient?
When is this approach convenient?
For I/O heavy applications
When is this approach convenient?
For I/O heavy applications
JavaScript was built for the Browser, which is I/O heavy!
But why?
But why?
You just have to schedule async I/O and you will get notified when the operation is completed!
But why?
You just have to schedule async I/O and you will get notified when the operation is completed!
No explicit thread creation!
In fact, the "user" code runs in a single thread!
How?
How?
Thanks to the event loop!
How?
Thanks to the event loop!
It executes I/O efficiently in the background
If you have to do 3 requests...
If you have to do 3 requests...
"user" thread
time
Event loop
If you have to do 3 requests...
"user" thread
time
Sched. req 1
Event loop
If you have to do 3 requests...
"user" thread
time
Sched. req 1
Event loop
If you have to do 3 requests...
"user" thread
time
Event loop
Sched. req 2
If you have to do 3 requests...
"user" thread
time
Event loop
Sched. req 2
If you have to do 3 requests...
"user" thread
time
Event loop
Sched. req 3
If you have to do 3 requests...
"user" thread
time
Event loop
Sched. req 3
If you have to do 3 requests...
"user" thread
time
Event loop
idle
If you have to do 3 requests...
"user" thread
time
Event loop
idle
req 1 result
If you have to do 3 requests...
"user" thread
time
Event loop
idle
If you have to do 3 requests...
"user" thread
time
Event loop
idle
idle
If you have to do 3 requests...
"user" thread
time
Event loop
idle
idle
req 3 result
If you have to do 3 requests...
"user" thread
time
Event loop
idle
idle
If you have to do 3 requests...
"user" thread
time
Event loop
idle
idle
idle
If you have to do 3 requests...
"user" thread
time
Event loop
idle
idle
idle
req 2 result
If you have to do 3 requests...
"user" thread
time
Event loop
idle
idle
idle
If you have to do 3 requests...
"user" thread
time
Event loop
idle
idle
idle
Simpler code for the user
If you have to do 3 requests...
"user" thread
time
Event loop
idle
idle
idle
Simpler code for the user
idle time only in one thread
This was a gross simplification...
Watch loige.link/event-loop-what-the-heck
if you want to go more in depth!
Since async is so fundamental there are many abstractions to handle async flow:
Ecosystem
Universal / Isomorphic web development
If you use JavaScript & Node.js you can build full stack web applications (frontend + backend) using only one language!
Bonus:
Javascript is one of the fastest scripting languages
Some resources:
⚠️ WARNING
JavaScript is a pragmatic and beautiful language, but like everything, it's far from perfect and it has many quirks...
JavaScript WAT, a short talk by Gary Bernhardt
loige.link/js-wat
Node.js is an open-source, cross-platform, JavaScript runtime environment that executes JavaScript code outside a web browser.
Created and launched in 2009 by Ryan Dahl to have a way to run JavaScript code outside a browser.
npm was launched in the same year.
Big companies (Linkedin, Uber, Paypal, Walmart) adopt Node.js early on.
In 2015 the Node.js foundation (now OpenJS) is born. (1)
Ryan Dahl
(in a T-shirt!)
Thanks to @gbinside, @StefanoAbalsamo, @PadraigOBrien, @mariocasciaro & @hernandezlobera
for reviews and feedback!