lucifer
full stack coder
by lucifer@duiba
everything you should know before you dive into nodejs
About Me
live slide
why nodejs
what is nodejs
what can nodejs do
nodejs - the core
why not rails ,php, java and so on ?
based on v8 and libuv
nodejs擅于处理高并发(异步非阻塞)
数据来源:https://gist.github.com/jboner/2841832
同步IO是主流开发模式
通过多进程或者多线程增加QPS
how about others ?
node中的众多模块都继承自EventEmitter。
事件并不是异步的。
非阻塞 != 异步
异步是非阻塞的核心。
libuv提供异步IO实现非阻塞
事件驱动指的是事件是一切的基础
ajax是一个事件
一次文件读取是一个事件
一个请求响应是一个事件
......
A nonblocking call returns immediately with whatever data are available: the full number of bytes requested, fewer, or none at all.
An asynchronous call requests a transfer that will be performed in its whole(entirety) but will complete at some future time.
阻塞 | 非阻塞 | |
---|---|---|
同步 | read | |
异步 | select/poll/epoll | aio |
Event Loop in nodejs
Node.js 不是一门语言也不是框架,它只是基于 Google V8 引擎的 JavaScript 运行时环境,同时结合 libuv 扩展了 JavaScript 功能,使得 JavaScript 能够同时具有 DOM 操作(浏览器)和 I/O、文件读写、操作数据库(服务器端)等能力,是目前最简单的全栈式语言。
V8 解释并执行 JavaScript 代码(这就是为什么浏览器能执行 JavaScript 原因)
libuv 由事件循环和线程池组成,负责所有 I/O 任务的分发与执行
Node.js Bindings就是将 Chrome V8 等暴露的C/C++ 接口转成JavaScript api
libuv is a multi-platform support library with a focus on asynchronous I/O.
global.__filename
global.__dirname
global.module
global.require()
global.process(接下来讲)
process.pid
process.versions
process.arch
process.env
process.argv
process.memoryUsage()
process.cwd()
process.exit()
process.kill(pid)
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
myEmitter.emit('event');
事件是基于发布者/订阅者模式
发送/监听事件本质上是高阶函数
emitter.listeners(eventName)
emitter.on(eventName, listener)
emitter.once(eventName, listener)
emitter.removeListener(eventName, listener)
实例方法
“Streams are Node’s best and most misunderstood idea.”
— Dominic Tarr
$ grep -d recurse done ./bin | wc -l
8
强大的linux管道
const grep = ... // A stream for the grep output
const wc = ... // A stream for the wc input
grep.pipe(wc)
流就是数据的集合 — 有点像数组一样. 不同之处在于流的数据不是一次到位的,而是连续的
buffer是一个很小的物理存储,通常是RAM。
在这里数据被收集起来,等待最终被发出并处理
一个例子🌰
vedio.on('data', chunk => {
if (chunk.size > 1024 * 1024) { // 1024 kb
vedio.resume()
} else {
vedio.pause();
}
})
const fs = require('fs');
const USER_NUM = 10;
const FILE_NAME = '~/Photoshop.dmg'
for (let i = 0; i < USER_NUM; i++) {
fs.readFile(FILE_NAME, (err, data) => {
if (err) {
console.error(err)
}
console.log(data)
})
}
const fs = require('fs');
const USER_NUM = 10;
const FILE_NAME = '~/Photoshop.dmg'
for (let i = 0; i < USER_NUM; i++) {
const instream = fs.createReadStream(FILE_NAME);
instream.on('data', console.log)
}
读取大文件的例子
const readable = getReadableStreamSomehow();
readable.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes of data.`);
});
Readable Stream - Flowing Mode
$ node stdin.js
const myReadable = new MyReadable(dataSource);
myReadable.setEncoding('utf8');
myReadable.on('readable', () => {
let chunk;
while (null !== (chunk = myReadable.read())) {
console.log(`Received ${chunk.length} bytes of data.`);
}
});
Readable Stream - Non-Flowing Mode
Writable Stream
var r = fs.createReadStream('file.txt')
var z = zlib.createGzip()
var w = fs.createWriteStream('file.txt.gz')
// Readable.pipe takes writable and returns destination
r.pipe(z).pipe(w)
Readable.prototype.pipe = function(writable, options) {
this.on('data', (chunk) => {
let ok = writable.write(chunk);
// 背压,暂停
!ok && this.pause();
});
this.on('end', () => {
writable.end()
})
writable.on('drain', () => {
// 恢复
this.resume();
});
// 支持链式调用
return this;
};
nodejs 集群与稳定性
By lucifer
nodejs for beginner