Downtown ReactJS Meetup - 2018/08/28
Concurrency vs Parallelism
Evented Model / Event Loop
V8 / DOM
React Reconciliation / Redux-Saga Async Effects
OS vs Userland
two or more tasks can start, run, and complete in overlapping time periods. It doesn't rule out that the tasks can be both be running at the same instant. For example, multitasking on a single- vs multi-core machine.
... a property of a program or system
tasks literally run at the same time e.g., on a multicore processor.
parallelism as the run-time behaviour of executing multiple tasks at the same time
Multi-tasking
-is a Process
-top-level execution container
-have their own memory space
-communicate with other processes via IPC
-sandbox / safety
Multi-threading
-runs inside a process
-share same memory
-need to manage sync
OS vs Userland
if (x == 5) // The "Check"
{
y = x * 2; // The "Act"
// If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
// y will not be equal to 10.
}
// Obtain lock for x
if (x == 5)
{
y = x * 2; // Now, nothing can change x until the lock is released.
// Therefore y = 10
}
// release lock for x
Multi-Threading
race condition
Sync | Async | |
---|---|---|
Single Threaded | Sequential | Interleaved |
Multi-Threaded | Parallel | Interleaved-Parallel |
Race conditions cannot happen
"Everything runs in parallel except your code"
one operation is executed at a time
write code to make it behave asynchronous
a thread is much lighter than a process, a function call is much lighter than a thread. Call functions instead of creating threads
functions run one at a time, never two in parallel.
in a single process, only one scope of code is running at a time.
the OS Scheduler does not come and pause this function and switch to another one, unless it pauses the process to give time to another process, not another thread in our process.
a process can handle tens of thousands of requests at a time as long as the system has enough resources (RAM, Network, etc.).
How those functions run is THE KEY DIFFERENCE.
// Example 1 - Synchronous (blocks) - Ruby
response = Faraday.get 'http://www.google.com'
puts response
puts 'Done!'
// Example 2 - Asynchronous (doesn't block)
request('http://www.google.com', function(error, response, body) {
console.log(body);
});
console.log('Done!');
Promise.all([apiRequest(...), fs.readFileAsync(...), readTemperature(...)])
.then(function(results) {
// all results in the results array here
// processing can continue using the results of all three async operations
}, function(err) {
// an error occurred, process the error here
}
);
A programming paradigm in which the flow of the program is determined by events such as user actions (mouse clicks, key presses), sensor outputs, or messages from other programs/threads.
In an event-driven application, there is generally a main loop that listens for events, and then triggers a callback function when one of those events is detected
Timers
executes callbacks scheduled by setTimeout() and setInterval().
const fs = require('fs');
function someAsyncOperation(callback) {
// Assume this takes 95ms to complete
fs.readFile('/path/to/file', callback);
}
const timeoutScheduled = Date.now();
setTimeout(() => {
const delay = Date.now() - timeoutScheduled;
console.log(`${delay}ms have passed since I was scheduled`);
}, 100);
// do someAsyncOperation which takes 95 ms to complete
someAsyncOperation(() => {
const startCallback = Date.now();
// do something that will take 10ms...
while (Date.now() - startCallback < 10) {
// do nothing
}
});
Pending Callbacks
executes I/O callbacks deferred to the next loop iteration.
Idle, Prepare
used internally
Poll
Check
setImmediate() callbacks are invoked here
Close Callbacks
some close callbacks, e.g. socket.on('close', ...).
Single Threaded
Synchronous Execution
Asynchronously Written
Promises
async function asyncFun () {
var value = await Promise
.resolve(1)
.then(x => x * 3)
.then(x => x + 5)
.then(x => x / 2);
return value;
}
asyncFun().then(x => console.log(`x: ${x}`));
// <- 'x: 4'
// Sequential
await someCall();
await anotherCall();
// Async push -- Sync wait
var taskA = someCall();
var taskB = someOtherCall();
await taskA;
await taskB;
// Parallel
Promise.all([taskA, taskB])
api(function(result){
api2(function(result2){
api3(function(result3){
// do work
});
});
});
api().then(function(result){
return api2();
}).then(function(result2){
return api3();
}).then(function(result3){
// do work
});
Promise.all([api(), api2(), api3()]).then(function(result) {
//do work. result is an array contains the values of the three fulfilled promises.
}).catch(function(error) {
//handle the error. At least one of the promises rejected.
});
document.
body
getElementById
getElementsByClassName
addEventListener
etc
html is text. DOM is in-memory representation of html text
DOM is tree-structured
DOM trees are easy to traverse
ENTER THE SPA
need to manipulate the tree A LOT!!
OS vs Userland
*Facebook did not invent this
Cheng Lou - On the Spectrum of Abstraction at react-europe 2016
It is a key goal for React that the amount of the user code that executes before yielding back into React is minimal.
This ensures that React retains the capability to schedule and split work in chunks according to what it knows about the UI.
OS vs Usercode
consequence:
-userland functions are not called directly
-react calls your function
-"pull" based
A push-based approach requires the programmer to decide how to schedule work.
nothing new. implementation of a very good idea
React Elements -- createElement
-atoms of the vDom
-immutability
-stateless
React Components -- createClass
-stateful
-don't have access to vDom -> needs to be converted to React Elements
class Hello extends React.Component {
// add state here
render() {
return React.createElement('div', null, `Hello ${this.props.toWhat}`);
}
}
ReactDOM.render(
React.createElement(Hello, {toWhat: 'World'}, null),
document.getElementById('root')
);
elements of different type
-roots differ
elements of same type
-attributes differ
-lifecycle hooks
recursing on children
The mental model of a saga is like a separate thread in your application that's solely responsible for side effects.
asynchronous things like data fetching and impure things like accessing the browser cache
it is middleware, which means that the thread can be started, paused and cancelled from the main application with normal redux actions, it has access to the full redux application state and it can dispatch redux actions as well.
Similar to Communication Sequential Processes (CSP)
-supports channels, async
Similar to Actor Model
-DOES NOT: parent/child, sender/receiver communication, retry/recovery patterns
-DOES: react to changes
Similar to Coroutines
-DOES NOT: have it's own stack
-DOES: pass control to another suspended generator
OS vs Userland
isolated thread
-code lives in its own file
-some APIs are not accessible (i.e. DOM)
postMessage
-communicates with the Main Thread
Spawn other workers (sub-workers)
isolated thread
-code lives in its own file
-some APIs are not accessible (i.e. DOM)
postMessage
-communicates with the Main Thread
Spawn other workers (sub-workers)
main
worker
Async Rendering
You're only as good as the problems you solve
Write code for other humans
- NOT for IDEs
- NOT for Version Control
- NOT for Machines
How you write has a direct impact on how your application will run
Independent of technology your application is only as good as the developers skills set
Always be learning