SlideShare a Scribd company logo
1 of 30
Download to read offline
Event Loop & EventEmitter
simen
simenkid@gmail.com
github.com/simenkid
Materials
• Demo Code
▫ https://github.com/simenkid/talks
• Read More…
▫ https://simeneer.blogspot.tw/2016/09/nodejs-eventemitter.html
Is Node.js Single Threaded?
• Let’s run a simple http server
var http = require('http');
var server = http.createServer(function (req, res) {
// Request Handler
});
server.listen(3000);
“… Actually only your ‘userland’ code runs in one thread.
… Node.js in fact spins up a number of threads.”
- D. Khan, “How to track down CPU issues in Node.js”
01_server.js
Concurrency
“Concurrency is a way to structure a thing so that you can, maybe, use
parallelism to do a better job. But parallelism is not the goal of
concurrency; concurrency's goal is a good structure.”
- R. Pike, Golang co-inventor
TCP
Server
TCP
Server
Tasks spread over threads Tasks spread over time
Requests
Requests
t
t
Blocking and Non-Blocking I/O
• Simplified concepts of
▫ Blocking I/O
▫ Non-blocking I/O
• I/O multiplexing
▫ Reactor
▫ select() or poll()
▫ Event notification, synchronous event demux
Reactor Pattern
Event Queue
Event Demux
(i.e., select()
CallbackI/O Request
register() Callback Execution
Reactor
Non-Blocking I/O Engine
• libuv
▫ Node.js, Luvit, …
▫ multi-platform support library with a focus on
asynchronous I/O
http://docs.libuv.org/
Linux OSX, BSDs SunOS Windows
Phases In the Loop
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
uv__run_timers()
uv__run_pending()
uv__run_idle()
uv__run_prepare()
uv__io_poll()
uv__run_check()
uv__run_closing_handles()
libuv core.c
int uv_run(uv_loop_t* loop, uv_run_mode mode) {
// ...
r = uv__loop_alive(loop);
// ...
while (r != 0 && loop->stop_flag == 0) {
uv__update_time(loop);
uv__run_timers(loop);
ran_pending = uv__run_pending(loop);
uv__run_idle(loop);
uv__run_prepare(loop);
timeout = 0;
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
timeout = uv_backend_timeout(loop);
uv__io_poll(loop, timeout);
uv__run_check(loop);
uv__run_closing_handles(loop);
if (mode == UV_RUN_ONCE) {
uv__update_time(loop);
uv__run_timers(loop);
}
r = uv__loop_alive(loop);
// ...
} https://github.com/libuv/libuv/blob/v1.x/src/unix/core.c#L332-L372
core.c
Event Loop in Node.js (I)
// Entry point for new node instances, ...
static void StartNodeInstance(void* arg) {
// ...
{
SealHandleScope seal(isolate);
bool more;
do {
v8::platform::PumpMessageLoop(default_platform, isolate);
more = uv_run(env->event_loop(), UV_RUN_ONCE);
if (more == false) {
v8::platform::PumpMessageLoop(default_platform, isolate);
EmitBeforeExit(env);
// Emit `beforeExit` if the loop became alive either after emitting
// event, or after running some callbacks.
more = uv_loop_alive(env->event_loop());
if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0)
more = true;
}
} while (more == true);
}
// ...
}
node.cc
Event Loop in Node.js (II)
Environment* CreateEnvironment(
Isolate* isolate,
uv_loop_t* loop,
// ...
const char* const* exec_argv)
{
// ...
uv_check_init(env->event_loop(), env->immediate_check_handle());
uv_unref(
reinterpret_cast<uv_handle_t*>(env->immediate_check_handle()));
uv_idle_init(env->event_loop(), env->immediate_idle_handle());
uv_prepare_init(env->event_loop(), env->idle_prepare_handle());
uv_check_init(env->event_loop(), env->idle_check_handle());
uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_prepare_handle()));
uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_check_handle()));
// Register handle cleanups
env->RegisterHandleCleanup(
reinterpret_cast<uv_handle_t*>(env->immediate_check_handle()),
HandleCleanup,
nullptr);
// ...
return env;
}
node.cc
Each node instance has its own event loop.
Put Tasks/Callbacks To Event Loop
• Non-blocking I/O APIs
▫ fs.readFile(path, cb)
• Timer Phase
▫ setTimeout(cb, time)
▫ setInterval(cb, time)
• Check Phase
▫ setImmediate(cb)
• At Each Phase End
▫ process.nextTick(cb)
▫ Microtasks (Promise)
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ poll │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
process.nextTick()
Microtasks
[ ]
“Each phase has a FIFO queue of callbacks to execute.”
How Long a Tick Is?
“This is a tick: the synchronous invocation of zero or more callback
functions associated with any external events. Once the queue is
emptied out and the last function returns, the tick is over.”
- josh3736, “What exactly is a Node.js event loop tick?” Answered@stackoverflow
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ poll │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
I/O Starvation
function crazy() {
console.log('Are you crazy?');
process.nextTick(function () {
crazy();
});
}
crazy();
[ ]
[ ]
[ ]
crazy()
nextTickQueue
“ … any time you call process.nextTick() in a given phase, all callbacks
passed to process.nextTick() will be resolved before the event loop
continues. … "starve" your I/O by making recursive process.nextTick()
calls, …”
EventEmitter
EventEmitter
function EventEmitter() {
EventEmitter.init.call(this);
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
// ...
EventEmitter.init = function() {
// ...
if (!this._events || this._events === Object.getPrototypeOf(this)._events) {
this._events = {};
this._eventsCount = 0;
}
this._maxListeners = this._maxListeners || undefined;
};
The base class accommodates Observer Pattern in Node.js
(Publish/Subscribe, Mediator Patterns)
events.js
APIs
EventEmitter.prototype.setMaxListeners
EventEmitter.prototype.getMaxListeners
EventEmitter.prototype.emit (publish)
EventEmitter.prototype.addListener (subscribe)
EventEmitter.prototype.on = EventEmitter.prototype.addListener
EventEmitter.prototype.once
EventEmitter.prototype.removeListener
EventEmitter.prototype.removeAllListeners
EventEmitter.prototype.listeners
EventEmitter.prototype.listenerCount
events.js
.on( )
EventEmitter.prototype.addListener = function addListener(type, listener) {
var m;
var events;
var existing;
if (typeof listener !== 'function')
throw new TypeError('listener must be a function');
events = this._events;
// ...
if (!existing) {
// Optimize the case of one listener.
// Don't need the extra array object.
existing = events[type] = listener;
++this._eventsCount;
} else {
if (typeof existing === 'function') {
// Adding the second element, need to change to array.
existing = events[type] = [existing, listener];
} else {
// If we've already got an array, just append.
existing.push(listener);
}
// ...
}
return this;
};
event_name1: [ ]
event_name3: [ ]
event_name2:
events.js
.emit( )
EventEmitter.prototype.emit = function emit(type) {
// ...
events = this._events;
// ...
handler = events[type];
if (!handler)
return false;
// ...
switch (len) {
// fast cases
case 1:
emitNone(handler, isFn, this);
break;
case 2:
emitOne(handler, isFn, this, arguments[1]);
break;
// ...
// slower
default:
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
emitMany(handler, isFn, this, args);
}
// ...
return true;
};
function emitMany(handler, isFn, self, args) {
if (isFn)
handler.apply(self, args);
else {
var len = handler.length;
var listeners = arrayClone(handler, len);
for (var i = 0; i < len; ++i)
listeners[i].apply(self, args);
}
}
event_name1: [ ]
event_name3: [ ]
event_name2:
events.js
Quick Demo
Who Prints First?
console.log('<0> schedule with setTimeout in 1-sec');
setTimeout(function () { console.log('[0] setTimeout in 1-sec boom!'); }, 1000);
console.log('<1> schedule with setTimeout in 0-sec');
setTimeout(function () { console.log('[1] setTimeout in 0-sec boom!'); }, 0);
console.log('<2> schedule with setImmediate');
setImmediate(function () { console.log('[2] setImmediate boom!'); });
console.log('<3> A immediately resolved promise');
aPromiseCall().then(function () { console.log('[3] promise resolve boom!'); });
console.log('<4> schedule with process.nextTick');
process.nextTick(function () { console.log('[4] process.nextTick boom!'); });
function aPromiseCall () {
return new Promise(function(resolve, reject) { return resolve(); });
}
What if these things are arranged in an I/O callback?
02_prints.js
EventEmitter - Dead Loop
var EventEmitter = require('events');
var crazy = new EventEmitter();
crazy.on('event1', function () {
console.log('event1 fired!');
crazy.emit('event2');
});
crazy.on('event2', function () {
console.log('event2 fired!');
crazy.emit('event3');
});
crazy.on('event3', function () {
console.log('event3 fired!');
crazy.emit('event1');
});
crazy.emit('event1');
event1
event2event3
Synchronous Execution Loop
What if scheduled with…
• process.nextTick()
• setImmediate()
03_deadloop.js
Long-Running Tasks?
• How to deal with my long-running tasks?
▫ Cut it down or use a worker
• A ridiculous heavy task
function doHeavy () {
// Counts how many 1s occurred
var count = 0;
for (var i = 0; i < 1e8; i++) {
if (Math.round(Math.log(
Math.sqrt(Math.abs(Math.round(Math.random() * 1000)))
)) === 1)
count++;
}
return count;
}
setInterval(function () { console.log('I am not blocked'); }, 1000);
console.log(doHeavy()); // Takes around 10 seconds on my machine
04_heavy.js
Cut It Down (I)
function doNotSoHeavy (times) {
var count = 0;
for (var i = 0; i < times; i++) {
if (Math.round(Math.log(
Math.sqrt(Math.abs(Math.round(Math.random() * 1000)))
)) === 1)
count++;
}
return count;
}
function doHeavy() {
var total = 1e8,
cuts = 100,
counts = 0;
for (var i = 0; i < cuts; i++) {
counts = counts + doNotSoHeavy(total/cuts);
}
return counts;
}
setInterval(function () { console.log('I am not blocked'); }, 1000);
console.log(doHeavy()); // Takes around 10 seconds on my machine
Synchronous. Blocks?
04_heavy_cut_sync.js
Cut It Down (II)
function doHeavy(callback) {
var total = 1e8,
cuts = 100,
counts = 0,
remains = cuts;
for (var i = 0; i < cuts; i++) {
setImmediate(function () {
counts = counts + doNotSoHeavy(total/cuts);
remains--;
if (!remains) {
process.nextTick(function () {
callback(counts);
});
}
});
}
}
doHeavy(function (counts) {
console.log(counts);
});
Need a callback to get the asynchronous result
Asynchronous. Blocks?
04_heavy_cut_async1.js
Cut It Down (III)
function doHeavy(callback) {
var total = 1e8,
cuts = 100,
counts = 0,
remains = cuts;
function doPerLoopIter() {
setImmediate(function () {
counts = counts + doNotSoHeavy(total/cuts);
remains--;
if (!remains) {
process.nextTick(function () {
callback(counts);
});
} else {
doPerLoopIter();
}
});
}
doPerLoopIter();
}
doHeavy(function (counts) {
console.log(counts);
});
Asynchronous. Blocks?
04_heavy_cut_async2.js
Cut It Down (IV)
var heavyJobs = {
counts: 0,
queue: [],
_callback: null,
add: function (task) {
this.queue.push(task);
},
next: function (callback) {
var self = this,
task = this.queue.shift();
if (!task) return;
setImmediate(function () {
self.counts = self.counts + task();
if (self.queue.length === 0)
self._callback(self.counts);
else
self.next();
});
},
do: function (callback) {
this._callback = callback;
this.next();
}
};
var total = 1e8,
cuts = 100;
for (var i = 0; i < cuts; i++) {
heavyJobs.add(function () {
return doNotSoHeavy(total/cuts);
});
}
setInterval(function () {
console.log('I am not blocked');
}, 1000);
heavyJobs.do(function (counts) {
console.log(counts);
});
There are many ways to make your
heavy jobs happy…
04_heavy_queue.js
This example is for demonstrating
the idea. Not very thoughtful.
Run With Another Process
var fork = require('child_process').fork;
function doHeavyWithWorker(callback) {
var worker = fork('./heavy_jobs.js');
worker.once('message', function (counts) {
callback(counts);
});
}
setInterval(function () {
console.log('I am not blocked');
}, 1000);
doHeavyWithWorker(function (result) {
console.log(result.counts);
});
// heavy_jobs.js
function doHeavy () {
// Counts how many 1s occurred
var count = 0;
for (var i = 0; i < 1e8; i++) {
if (Math.round(Math.log(
Math.sqrt(Math.abs(
Math.round(Math.random() * 1000))
)
)) === 1)
count++;
}
return count;
}
var counts = doHeavy();
process.send({
counts: counts
});
fork() establishes the IPC channel between parent and child for your convenience to
run your node.js code. There are others ways to do such a job with child_process.
05_heavy_fork.js heavy_jobs.js
That's It!
Thank You!

More Related Content

What's hot

Profiling your Applications using the Linux Perf Tools
Profiling your Applications using the Linux Perf ToolsProfiling your Applications using the Linux Perf Tools
Profiling your Applications using the Linux Perf Tools
emBO_Conference
 

What's hot (20)

Windows Registered I/O (RIO) vs IOCP
Windows Registered I/O (RIO) vs IOCPWindows Registered I/O (RIO) vs IOCP
Windows Registered I/O (RIO) vs IOCP
 
Dll 분석 방법
Dll 분석 방법Dll 분석 방법
Dll 분석 방법
 
[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요
[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요
[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요
 
Microsoft Silverlight - An Introduction
Microsoft Silverlight - An IntroductionMicrosoft Silverlight - An Introduction
Microsoft Silverlight - An Introduction
 
Virtual machine and javascript engine
Virtual machine and javascript engineVirtual machine and javascript engine
Virtual machine and javascript engine
 
Click jacking
Click jackingClick jacking
Click jacking
 
A real-world example of Functional Programming with fp-ts - no experience req...
A real-world example of Functional Programming with fp-ts - no experience req...A real-world example of Functional Programming with fp-ts - no experience req...
A real-world example of Functional Programming with fp-ts - no experience req...
 
From DTrace to Linux
From DTrace to LinuxFrom DTrace to Linux
From DTrace to Linux
 
Management Zabbix with Terraform
Management Zabbix with TerraformManagement Zabbix with Terraform
Management Zabbix with Terraform
 
KGC 2016: HTTPS 로 모바일 게임 서버 구축한다는 것 - Korea Games Conference
KGC 2016: HTTPS 로 모바일 게임 서버 구축한다는 것 - Korea Games ConferenceKGC 2016: HTTPS 로 모바일 게임 서버 구축한다는 것 - Korea Games Conference
KGC 2016: HTTPS 로 모바일 게임 서버 구축한다는 것 - Korea Games Conference
 
Malware Analysis -an overview by PP Singh
Malware Analysis -an overview by PP SinghMalware Analysis -an overview by PP Singh
Malware Analysis -an overview by PP Singh
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and Hobgoblins
 
〈야생의 땅: 듀랑고〉 서버 아키텍처 Vol. 3
〈야생의 땅: 듀랑고〉 서버 아키텍처 Vol. 3〈야생의 땅: 듀랑고〉 서버 아키텍처 Vol. 3
〈야생의 땅: 듀랑고〉 서버 아키텍처 Vol. 3
 
skipfish
skipfishskipfish
skipfish
 
OWASP ZAP Workshop for QA Testers
OWASP ZAP Workshop for QA TestersOWASP ZAP Workshop for QA Testers
OWASP ZAP Workshop for QA Testers
 
SIP Tutorial/Workshop 2
SIP Tutorial/Workshop 2SIP Tutorial/Workshop 2
SIP Tutorial/Workshop 2
 
A whirlwind tour of the LLVM optimizer
A whirlwind tour of the LLVM optimizerA whirlwind tour of the LLVM optimizer
A whirlwind tour of the LLVM optimizer
 
JavaScript Engines and Event Loop
JavaScript Engines and Event Loop JavaScript Engines and Event Loop
JavaScript Engines and Event Loop
 
PyconKR 2018 Deep dive into Coroutine
PyconKR 2018 Deep dive into CoroutinePyconKR 2018 Deep dive into Coroutine
PyconKR 2018 Deep dive into Coroutine
 
Profiling your Applications using the Linux Perf Tools
Profiling your Applications using the Linux Perf ToolsProfiling your Applications using the Linux Perf Tools
Profiling your Applications using the Linux Perf Tools
 

Viewers also liked

Viewers also liked (14)

Voltage Controlled Oscillator Design - Short Course at NKFUST, 2013
Voltage Controlled Oscillator Design - Short Course at NKFUST, 2013Voltage Controlled Oscillator Design - Short Course at NKFUST, 2013
Voltage Controlled Oscillator Design - Short Course at NKFUST, 2013
 
專題製作發想與報告撰寫技巧
專題製作發想與報告撰寫技巧專題製作發想與報告撰寫技巧
專題製作發想與報告撰寫技巧
 
Agilent ADS 模擬手冊 [實習2] 放大器設計
Agilent ADS 模擬手冊 [實習2]  放大器設計Agilent ADS 模擬手冊 [實習2]  放大器設計
Agilent ADS 模擬手冊 [實習2] 放大器設計
 
Agilent ADS 模擬手冊 [實習3] 壓控振盪器模擬
Agilent ADS 模擬手冊 [實習3] 壓控振盪器模擬Agilent ADS 模擬手冊 [實習3] 壓控振盪器模擬
Agilent ADS 模擬手冊 [實習3] 壓控振盪器模擬
 
全端物聯網探索之旅 - 重點整理版
全端物聯網探索之旅 - 重點整理版全端物聯網探索之旅 - 重點整理版
全端物聯網探索之旅 - 重點整理版
 
Phase-locked Loops - Theory and Design
Phase-locked Loops - Theory and DesignPhase-locked Loops - Theory and Design
Phase-locked Loops - Theory and Design
 
射頻電子實驗手冊 [實驗6] 阻抗匹配模擬
射頻電子實驗手冊 [實驗6] 阻抗匹配模擬射頻電子實驗手冊 [實驗6] 阻抗匹配模擬
射頻電子實驗手冊 [實驗6] 阻抗匹配模擬
 
Agilent ADS 模擬手冊 [實習1] 基本操作與射頻放大器設計
Agilent ADS 模擬手冊 [實習1] 基本操作與射頻放大器設計Agilent ADS 模擬手冊 [實習1] 基本操作與射頻放大器設計
Agilent ADS 模擬手冊 [實習1] 基本操作與射頻放大器設計
 
電路學 - [第三章] 網路定理
電路學 - [第三章] 網路定理電路學 - [第三章] 網路定理
電路學 - [第三章] 網路定理
 
Multiband Transceivers - [Chapter 7] Spec. Table
Multiband Transceivers - [Chapter 7]  Spec. TableMultiband Transceivers - [Chapter 7]  Spec. Table
Multiband Transceivers - [Chapter 7] Spec. Table
 
Multiband Transceivers - [Chapter 6] Multi-mode and Multi-band Transceivers
Multiband Transceivers - [Chapter 6] Multi-mode and Multi-band TransceiversMultiband Transceivers - [Chapter 6] Multi-mode and Multi-band Transceivers
Multiband Transceivers - [Chapter 6] Multi-mode and Multi-band Transceivers
 
Multiband Transceivers - [Chapter 7] Multi-mode/Multi-band GSM/GPRS/TDMA/AMP...
Multiband Transceivers - [Chapter 7]  Multi-mode/Multi-band GSM/GPRS/TDMA/AMP...Multiband Transceivers - [Chapter 7]  Multi-mode/Multi-band GSM/GPRS/TDMA/AMP...
Multiband Transceivers - [Chapter 7] Multi-mode/Multi-band GSM/GPRS/TDMA/AMP...
 
Multiband Transceivers - [Chapter 4] Design Parameters of Wireless Radios
Multiband Transceivers - [Chapter 4] Design Parameters of Wireless RadiosMultiband Transceivers - [Chapter 4] Design Parameters of Wireless Radios
Multiband Transceivers - [Chapter 4] Design Parameters of Wireless Radios
 
射頻電子實驗手冊 [實驗1 ~ 5] ADS入門, 傳輸線模擬, 直流模擬, 暫態模擬, 交流模擬
射頻電子實驗手冊 [實驗1 ~ 5] ADS入門, 傳輸線模擬, 直流模擬, 暫態模擬, 交流模擬射頻電子實驗手冊 [實驗1 ~ 5] ADS入門, 傳輸線模擬, 直流模擬, 暫態模擬, 交流模擬
射頻電子實驗手冊 [實驗1 ~ 5] ADS入門, 傳輸線模擬, 直流模擬, 暫態模擬, 交流模擬
 

Similar to Node.js Event Loop & EventEmitter

Tips on how to improve the performance of your custom modules for high volume...
Tips on how to improve the performance of your custom modules for high volume...Tips on how to improve the performance of your custom modules for high volume...
Tips on how to improve the performance of your custom modules for high volume...
Odoo
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
The event-driven nature of javascript – IPC2012
The event-driven nature of javascript – IPC2012The event-driven nature of javascript – IPC2012
The event-driven nature of javascript – IPC2012
Martin Schuhfuß
 

Similar to Node.js Event Loop & EventEmitter (20)

How NOT to write in Node.js
How NOT to write in Node.jsHow NOT to write in Node.js
How NOT to write in Node.js
 
Server side JavaScript: going all the way
Server side JavaScript: going all the wayServer side JavaScript: going all the way
Server side JavaScript: going all the way
 
Building Hermetic Systems (without Docker)
Building Hermetic Systems (without Docker)Building Hermetic Systems (without Docker)
Building Hermetic Systems (without Docker)
 
Node js lecture
Node js lectureNode js lecture
Node js lecture
 
Node.js System: The Landing
Node.js System: The LandingNode.js System: The Landing
Node.js System: The Landing
 
Alexander Reelsen - Seccomp for Developers
Alexander Reelsen - Seccomp for DevelopersAlexander Reelsen - Seccomp for Developers
Alexander Reelsen - Seccomp for Developers
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.js
 
Tips on how to improve the performance of your custom modules for high volume...
Tips on how to improve the performance of your custom modules for high volume...Tips on how to improve the performance of your custom modules for high volume...
Tips on how to improve the performance of your custom modules for high volume...
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
 
Douglas Crockford: Serversideness
Douglas Crockford: ServersidenessDouglas Crockford: Serversideness
Douglas Crockford: Serversideness
 
Workshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptWorkshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScript
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
 
Jaap : node, npm & grunt
Jaap : node, npm & gruntJaap : node, npm & grunt
Jaap : node, npm & grunt
 
Node.js - async for the rest of us.
Node.js - async for the rest of us.Node.js - async for the rest of us.
Node.js - async for the rest of us.
 
To Err Is Human
To Err Is HumanTo Err Is Human
To Err Is Human
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)
 
The event-driven nature of javascript – IPC2012
The event-driven nature of javascript – IPC2012The event-driven nature of javascript – IPC2012
The event-driven nature of javascript – IPC2012
 
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak   CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
CONFidence 2015: DTrace + OSX = Fun - Andrzej Dyjak
 
Java util concurrent
Java util concurrentJava util concurrent
Java util concurrent
 

More from Simen Li

More from Simen Li (17)

2018 VLSI/CAD Symposium Tutorial (Aug. 7, 20:00-21:00 Room 3F-VII)
2018 VLSI/CAD Symposium Tutorial (Aug. 7, 20:00-21:00 Room 3F-VII)2018 VLSI/CAD Symposium Tutorial (Aug. 7, 20:00-21:00 Room 3F-VII)
2018 VLSI/CAD Symposium Tutorial (Aug. 7, 20:00-21:00 Room 3F-VII)
 
ADF4113 Frequency Synthesizer 驅動程式實作
ADF4113 Frequency Synthesizer 驅動程式實作ADF4113 Frequency Synthesizer 驅動程式實作
ADF4113 Frequency Synthesizer 驅動程式實作
 
射頻電子實驗手冊 - [實驗8] 低雜訊放大器模擬
射頻電子實驗手冊 - [實驗8] 低雜訊放大器模擬射頻電子實驗手冊 - [實驗8] 低雜訊放大器模擬
射頻電子實驗手冊 - [實驗8] 低雜訊放大器模擬
 
射頻電子實驗手冊 - [實驗7] 射頻放大器模擬
射頻電子實驗手冊 - [實驗7] 射頻放大器模擬射頻電子實驗手冊 - [實驗7] 射頻放大器模擬
射頻電子實驗手冊 - [實驗7] 射頻放大器模擬
 
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
 
[ZigBee 嵌入式系統] ZigBee 應用實作 - 使用 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee 應用實作 - 使用 TI Z-Stack Firmware[ZigBee 嵌入式系統] ZigBee 應用實作 - 使用 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee 應用實作 - 使用 TI Z-Stack Firmware
 
[嵌入式系統] MCS-51 實驗 - 使用 IAR (3)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (3)[嵌入式系統] MCS-51 實驗 - 使用 IAR (3)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (3)
 
[嵌入式系統] MCS-51 實驗 - 使用 IAR (2)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (2)[嵌入式系統] MCS-51 實驗 - 使用 IAR (2)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (2)
 
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
 
深入淺出C語言
深入淺出C語言深入淺出C語言
深入淺出C語言
 
[嵌入式系統] 嵌入式系統進階
[嵌入式系統] 嵌入式系統進階[嵌入式系統] 嵌入式系統進階
[嵌入式系統] 嵌入式系統進階
 
Multiband Transceivers - [Chapter 5] Software-Defined Radios
Multiband Transceivers - [Chapter 5]  Software-Defined RadiosMultiband Transceivers - [Chapter 5]  Software-Defined Radios
Multiband Transceivers - [Chapter 5] Software-Defined Radios
 
Multiband Transceivers - [Chapter 3] Basic Concept of Comm. Systems
Multiband Transceivers - [Chapter 3]  Basic Concept of Comm. SystemsMultiband Transceivers - [Chapter 3]  Basic Concept of Comm. Systems
Multiband Transceivers - [Chapter 3] Basic Concept of Comm. Systems
 
Multiband Transceivers - [Chapter 2] Noises and Linearities
Multiband Transceivers - [Chapter 2]  Noises and LinearitiesMultiband Transceivers - [Chapter 2]  Noises and Linearities
Multiband Transceivers - [Chapter 2] Noises and Linearities
 
Multiband Transceivers - [Chapter 1]
Multiband Transceivers - [Chapter 1] Multiband Transceivers - [Chapter 1]
Multiband Transceivers - [Chapter 1]
 
RF Module Design - [Chapter 8] Phase-Locked Loops
RF Module Design - [Chapter 8] Phase-Locked LoopsRF Module Design - [Chapter 8] Phase-Locked Loops
RF Module Design - [Chapter 8] Phase-Locked Loops
 
RF Module Design - [Chapter 7] Voltage-Controlled Oscillator
RF Module Design - [Chapter 7] Voltage-Controlled OscillatorRF Module Design - [Chapter 7] Voltage-Controlled Oscillator
RF Module Design - [Chapter 7] Voltage-Controlled Oscillator
 

Recently uploaded

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 

Recently uploaded (20)

Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 

Node.js Event Loop & EventEmitter

  • 1. Event Loop & EventEmitter simen simenkid@gmail.com github.com/simenkid
  • 2. Materials • Demo Code ▫ https://github.com/simenkid/talks • Read More… ▫ https://simeneer.blogspot.tw/2016/09/nodejs-eventemitter.html
  • 3. Is Node.js Single Threaded? • Let’s run a simple http server var http = require('http'); var server = http.createServer(function (req, res) { // Request Handler }); server.listen(3000); “… Actually only your ‘userland’ code runs in one thread. … Node.js in fact spins up a number of threads.” - D. Khan, “How to track down CPU issues in Node.js” 01_server.js
  • 4. Concurrency “Concurrency is a way to structure a thing so that you can, maybe, use parallelism to do a better job. But parallelism is not the goal of concurrency; concurrency's goal is a good structure.” - R. Pike, Golang co-inventor TCP Server TCP Server Tasks spread over threads Tasks spread over time Requests Requests t t
  • 5. Blocking and Non-Blocking I/O • Simplified concepts of ▫ Blocking I/O ▫ Non-blocking I/O • I/O multiplexing ▫ Reactor ▫ select() or poll() ▫ Event notification, synchronous event demux
  • 6. Reactor Pattern Event Queue Event Demux (i.e., select() CallbackI/O Request register() Callback Execution Reactor
  • 7. Non-Blocking I/O Engine • libuv ▫ Node.js, Luvit, … ▫ multi-platform support library with a focus on asynchronous I/O http://docs.libuv.org/ Linux OSX, BSDs SunOS Windows
  • 8. Phases In the Loop ┌───────────────────────┐ ┌─>│ timers │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ I/O callbacks │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ idle, prepare │ │ └──────────┬────────────┘ ┌───────────────┐ │ ┌──────────┴────────────┐ │ incoming: │ │ │ poll │<─────┤ connections, │ │ └──────────┬────────────┘ │ data, etc. │ │ ┌──────────┴────────────┐ └───────────────┘ │ │ check │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ └──┤ close callbacks │ └───────────────────────┘ uv__run_timers() uv__run_pending() uv__run_idle() uv__run_prepare() uv__io_poll() uv__run_check() uv__run_closing_handles()
  • 9. libuv core.c int uv_run(uv_loop_t* loop, uv_run_mode mode) { // ... r = uv__loop_alive(loop); // ... while (r != 0 && loop->stop_flag == 0) { uv__update_time(loop); uv__run_timers(loop); ran_pending = uv__run_pending(loop); uv__run_idle(loop); uv__run_prepare(loop); timeout = 0; if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) timeout = uv_backend_timeout(loop); uv__io_poll(loop, timeout); uv__run_check(loop); uv__run_closing_handles(loop); if (mode == UV_RUN_ONCE) { uv__update_time(loop); uv__run_timers(loop); } r = uv__loop_alive(loop); // ... } https://github.com/libuv/libuv/blob/v1.x/src/unix/core.c#L332-L372 core.c
  • 10. Event Loop in Node.js (I) // Entry point for new node instances, ... static void StartNodeInstance(void* arg) { // ... { SealHandleScope seal(isolate); bool more; do { v8::platform::PumpMessageLoop(default_platform, isolate); more = uv_run(env->event_loop(), UV_RUN_ONCE); if (more == false) { v8::platform::PumpMessageLoop(default_platform, isolate); EmitBeforeExit(env); // Emit `beforeExit` if the loop became alive either after emitting // event, or after running some callbacks. more = uv_loop_alive(env->event_loop()); if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0) more = true; } } while (more == true); } // ... } node.cc
  • 11. Event Loop in Node.js (II) Environment* CreateEnvironment( Isolate* isolate, uv_loop_t* loop, // ... const char* const* exec_argv) { // ... uv_check_init(env->event_loop(), env->immediate_check_handle()); uv_unref( reinterpret_cast<uv_handle_t*>(env->immediate_check_handle())); uv_idle_init(env->event_loop(), env->immediate_idle_handle()); uv_prepare_init(env->event_loop(), env->idle_prepare_handle()); uv_check_init(env->event_loop(), env->idle_check_handle()); uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_prepare_handle())); uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_check_handle())); // Register handle cleanups env->RegisterHandleCleanup( reinterpret_cast<uv_handle_t*>(env->immediate_check_handle()), HandleCleanup, nullptr); // ... return env; } node.cc Each node instance has its own event loop.
  • 12. Put Tasks/Callbacks To Event Loop • Non-blocking I/O APIs ▫ fs.readFile(path, cb) • Timer Phase ▫ setTimeout(cb, time) ▫ setInterval(cb, time) • Check Phase ▫ setImmediate(cb) • At Each Phase End ▫ process.nextTick(cb) ▫ Microtasks (Promise) ┌───────────────────────┐ ┌─>│ timers │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ I/O callbacks │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ idle, prepare │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ poll │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ check │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ └──┤ close callbacks │ └───────────────────────┘ process.nextTick() Microtasks [ ] “Each phase has a FIFO queue of callbacks to execute.”
  • 13. How Long a Tick Is? “This is a tick: the synchronous invocation of zero or more callback functions associated with any external events. Once the queue is emptied out and the last function returns, the tick is over.” - josh3736, “What exactly is a Node.js event loop tick?” Answered@stackoverflow ┌───────────────────────┐ ┌─>│ timers │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ I/O callbacks │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ idle, prepare │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ poll │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ check │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ └──┤ close callbacks │ └───────────────────────┘ [ ] [ ] [ ] [ ] [ ] [ ]
  • 14. I/O Starvation function crazy() { console.log('Are you crazy?'); process.nextTick(function () { crazy(); }); } crazy(); [ ] [ ] [ ] crazy() nextTickQueue “ … any time you call process.nextTick() in a given phase, all callbacks passed to process.nextTick() will be resolved before the event loop continues. … "starve" your I/O by making recursive process.nextTick() calls, …”
  • 16. EventEmitter function EventEmitter() { EventEmitter.init.call(this); } module.exports = EventEmitter; // Backwards-compat with node 0.10.x EventEmitter.EventEmitter = EventEmitter; // ... EventEmitter.init = function() { // ... if (!this._events || this._events === Object.getPrototypeOf(this)._events) { this._events = {}; this._eventsCount = 0; } this._maxListeners = this._maxListeners || undefined; }; The base class accommodates Observer Pattern in Node.js (Publish/Subscribe, Mediator Patterns) events.js
  • 17. APIs EventEmitter.prototype.setMaxListeners EventEmitter.prototype.getMaxListeners EventEmitter.prototype.emit (publish) EventEmitter.prototype.addListener (subscribe) EventEmitter.prototype.on = EventEmitter.prototype.addListener EventEmitter.prototype.once EventEmitter.prototype.removeListener EventEmitter.prototype.removeAllListeners EventEmitter.prototype.listeners EventEmitter.prototype.listenerCount events.js
  • 18. .on( ) EventEmitter.prototype.addListener = function addListener(type, listener) { var m; var events; var existing; if (typeof listener !== 'function') throw new TypeError('listener must be a function'); events = this._events; // ... if (!existing) { // Optimize the case of one listener. // Don't need the extra array object. existing = events[type] = listener; ++this._eventsCount; } else { if (typeof existing === 'function') { // Adding the second element, need to change to array. existing = events[type] = [existing, listener]; } else { // If we've already got an array, just append. existing.push(listener); } // ... } return this; }; event_name1: [ ] event_name3: [ ] event_name2: events.js
  • 19. .emit( ) EventEmitter.prototype.emit = function emit(type) { // ... events = this._events; // ... handler = events[type]; if (!handler) return false; // ... switch (len) { // fast cases case 1: emitNone(handler, isFn, this); break; case 2: emitOne(handler, isFn, this, arguments[1]); break; // ... // slower default: args = new Array(len - 1); for (i = 1; i < len; i++) args[i - 1] = arguments[i]; emitMany(handler, isFn, this, args); } // ... return true; }; function emitMany(handler, isFn, self, args) { if (isFn) handler.apply(self, args); else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) listeners[i].apply(self, args); } } event_name1: [ ] event_name3: [ ] event_name2: events.js
  • 21. Who Prints First? console.log('<0> schedule with setTimeout in 1-sec'); setTimeout(function () { console.log('[0] setTimeout in 1-sec boom!'); }, 1000); console.log('<1> schedule with setTimeout in 0-sec'); setTimeout(function () { console.log('[1] setTimeout in 0-sec boom!'); }, 0); console.log('<2> schedule with setImmediate'); setImmediate(function () { console.log('[2] setImmediate boom!'); }); console.log('<3> A immediately resolved promise'); aPromiseCall().then(function () { console.log('[3] promise resolve boom!'); }); console.log('<4> schedule with process.nextTick'); process.nextTick(function () { console.log('[4] process.nextTick boom!'); }); function aPromiseCall () { return new Promise(function(resolve, reject) { return resolve(); }); } What if these things are arranged in an I/O callback? 02_prints.js
  • 22. EventEmitter - Dead Loop var EventEmitter = require('events'); var crazy = new EventEmitter(); crazy.on('event1', function () { console.log('event1 fired!'); crazy.emit('event2'); }); crazy.on('event2', function () { console.log('event2 fired!'); crazy.emit('event3'); }); crazy.on('event3', function () { console.log('event3 fired!'); crazy.emit('event1'); }); crazy.emit('event1'); event1 event2event3 Synchronous Execution Loop What if scheduled with… • process.nextTick() • setImmediate() 03_deadloop.js
  • 23. Long-Running Tasks? • How to deal with my long-running tasks? ▫ Cut it down or use a worker • A ridiculous heavy task function doHeavy () { // Counts how many 1s occurred var count = 0; for (var i = 0; i < 1e8; i++) { if (Math.round(Math.log( Math.sqrt(Math.abs(Math.round(Math.random() * 1000))) )) === 1) count++; } return count; } setInterval(function () { console.log('I am not blocked'); }, 1000); console.log(doHeavy()); // Takes around 10 seconds on my machine 04_heavy.js
  • 24. Cut It Down (I) function doNotSoHeavy (times) { var count = 0; for (var i = 0; i < times; i++) { if (Math.round(Math.log( Math.sqrt(Math.abs(Math.round(Math.random() * 1000))) )) === 1) count++; } return count; } function doHeavy() { var total = 1e8, cuts = 100, counts = 0; for (var i = 0; i < cuts; i++) { counts = counts + doNotSoHeavy(total/cuts); } return counts; } setInterval(function () { console.log('I am not blocked'); }, 1000); console.log(doHeavy()); // Takes around 10 seconds on my machine Synchronous. Blocks? 04_heavy_cut_sync.js
  • 25. Cut It Down (II) function doHeavy(callback) { var total = 1e8, cuts = 100, counts = 0, remains = cuts; for (var i = 0; i < cuts; i++) { setImmediate(function () { counts = counts + doNotSoHeavy(total/cuts); remains--; if (!remains) { process.nextTick(function () { callback(counts); }); } }); } } doHeavy(function (counts) { console.log(counts); }); Need a callback to get the asynchronous result Asynchronous. Blocks? 04_heavy_cut_async1.js
  • 26. Cut It Down (III) function doHeavy(callback) { var total = 1e8, cuts = 100, counts = 0, remains = cuts; function doPerLoopIter() { setImmediate(function () { counts = counts + doNotSoHeavy(total/cuts); remains--; if (!remains) { process.nextTick(function () { callback(counts); }); } else { doPerLoopIter(); } }); } doPerLoopIter(); } doHeavy(function (counts) { console.log(counts); }); Asynchronous. Blocks? 04_heavy_cut_async2.js
  • 27. Cut It Down (IV) var heavyJobs = { counts: 0, queue: [], _callback: null, add: function (task) { this.queue.push(task); }, next: function (callback) { var self = this, task = this.queue.shift(); if (!task) return; setImmediate(function () { self.counts = self.counts + task(); if (self.queue.length === 0) self._callback(self.counts); else self.next(); }); }, do: function (callback) { this._callback = callback; this.next(); } }; var total = 1e8, cuts = 100; for (var i = 0; i < cuts; i++) { heavyJobs.add(function () { return doNotSoHeavy(total/cuts); }); } setInterval(function () { console.log('I am not blocked'); }, 1000); heavyJobs.do(function (counts) { console.log(counts); }); There are many ways to make your heavy jobs happy… 04_heavy_queue.js This example is for demonstrating the idea. Not very thoughtful.
  • 28. Run With Another Process var fork = require('child_process').fork; function doHeavyWithWorker(callback) { var worker = fork('./heavy_jobs.js'); worker.once('message', function (counts) { callback(counts); }); } setInterval(function () { console.log('I am not blocked'); }, 1000); doHeavyWithWorker(function (result) { console.log(result.counts); }); // heavy_jobs.js function doHeavy () { // Counts how many 1s occurred var count = 0; for (var i = 0; i < 1e8; i++) { if (Math.round(Math.log( Math.sqrt(Math.abs( Math.round(Math.random() * 1000)) ) )) === 1) count++; } return count; } var counts = doHeavy(); process.send({ counts: counts }); fork() establishes the IPC channel between parent and child for your convenience to run your node.js code. There are others ways to do such a job with child_process. 05_heavy_fork.js heavy_jobs.js