oswaldo.herrera@WIZELINE.com
@wdonet
from node.university
Heap
Event Loop
Stack
Execution Context
Memory Allocation
Callback queue
onfocus callback()
onload callback()
onclick callback()
Web APIs
DOM
XMLHttpRequest
setTimeout
call1()
call3()
call2()
static uv_thread_t default_threads[4];
#define MAX_THREADPOOL_SIZE 128
phases
callbacks scheduled by
setTimeout() and setInterval()
IO related callbacks except those scheduled by timers and setImmediate()
used internally
setImmediate() callbacks
i.e. socket.on('close', ...)
retrieve new I/O events
or ticks
callback
resolve promise
next scheduled tick
LIBUV
A timer specifies a threshold
TIME
now
100ms
The poll phase controls when timers are executed
(as early as possible after the threshold)
setTimeout(() => {}, 100);
TIME
threshold
var fs = require('fs');
function someAsyncOperation (callback) {
// Assume this takes 95ms to complete
fs.readFile('/path/to/file', callback);
}
var timeoutScheduled = Date.now();
setTimeout(function () {
var delay = Date.now() - timeoutScheduled;
console.log(delay + "ms have passed since I was scheduled");
}, 100);
// do someAsyncOperation which takes 95 ms to complete
someAsyncOperation(function () {
var startCallback = Date.now();
// do something that will take 10ms...
while (Date.now() - startCallback < 10) {
; // do nothing
}
});
timeoutScheduled
100ms
setTimeout() callback
fs.readFile( f ) ends
95ms
10ms
f()
105ms
105ms have passed since I was scheduled
executes callbacks for some
system operations
(network - disk files - database connections)
ECONNREFUSED
ETIMEDOUT
i.e. TCP sockets
Jump to Check Phase
callback queue empty ?
Execute
do
WHILE
- callback exists, and
- OS hard limit not reached
YES
NO
NO
YES
Is there a script scheduled by setImmediate() ?
Execute
all timers who reached threshold
NO
YES
execute callbacks (almost) immediately
after the poll phase has completed
setImmediate( callback() )
If poll phase becomes idle, executes
at the check phase .
executes callbacks for
"close" events
and for
cleaning things
websocket.close()
EventEmitter.on('close', () => {})
i.e.
socket.end()
for setTimeout() & setInterval()
for IO related callbacks
for setImmediate() callbacks
for closing events
executes queued callback
( Again )
// timervsimmediate.js
setTimeout(function timeout () {
console.log('timeout');
},0);
setImmediate(function immediate () {
console.log('immediate');
});
// immediateOverTimer.js
var fs = require('fs')
fs.readFile(__filename, () => {
setTimeout(() => {
console.log('timeout')
}, 0)
setImmediate(() => {
console.log('immediate')
})
});
setImmediate() will always execute before any timer,
if it is scheduled within an I/O cycle
callback
resolve promise
next scheduled tick
nextTickQueue()
micro tasks
Callback queue
scheduled callback()
scheduled callback()
scheduled callback()
happens inside the same phase
// this has an asynchronous signature, but calls callback synchronously
function someAsyncApiCall (callback) { callback(); };
// the callback is called before `someAsyncApiCall` completes.
someAsyncApiCall(() => {
// since someAsyncApiCall has completed, bar hasn't been assigned any value
console.log('bar', bar); // undefined
});
var bar = 1;
function someAsyncApiCall (callback) {
process.nextTick(callback);
};
someAsyncApiCall(() => {
console.log('bar', bar); // 1
});
var bar = 1;
would work ?
and this ?
function apiCall (arg, callback) {
if (typeof arg !== 'string')
return process.nextTick(callback,
new TypeError('argument should be string'));
}
real life examples
const server = net.createServer(() => {}).listen(8080);
server.on('listening', () => {});
Executes at same phase
Main reasons:
- Cleaning : error handling, unnecessary resources cleaning or re-try request
- Run operations before loop continues
Executes at next tick (phase)
Compatible with browser JS and + environments
Easier to reason about