此栏最终目标
认知Buffer认知Stream认知Eventsnode中的自上而下第一类科学知识关键点
认知BufferArrayBuffer通用型的、一般来说宽度的原初十进制统计数据头文件,不能间接操作方式,而要透过类别字符串第一类(TypedArray)操作方式,将头文件中的Luzy为某一的文件格式。能将其认知为几块缓存,具体文本存甚么须要其它的新闻稿const buffer = new rrayBuffer(8)
        console.log(buffer) // ArrayBuffer { [Uint8Contents]:<00 00 00 00 00 00 00 00>,[byteLength]:8 }
        const int16Buffer = new Int16Array(buffer)
        console.log(int16Buffer) // Int16Array(4) [0,0,0,0]
        
    
    2. Unit8Array
则表示两个8位的无记号auth字符串,建立的这时候文本被调用为0const unit8 = new Uint8Array(2)
        unit8[0] = 42
        console.log(unint8[0]) // 42
        console.log(unit8.length) // 2console.log(unit8.BYTES_PER_ELEMENT) // 1
        
        const arr = new Uint8Array([21,31])
        console.log(arr[1]) // 31
        
    
    3. ArrayBuffer与TypedArray的关系
    TypedArray:Uint8Array, Int32Array, Int16Array
    ArrayBuffer: 本身是两个0、1存放在一行里的集合
关系:使用TypedArray划分ArrayBuffer中的十进制字节,4. node中使用Buffer
    Buffer实现了Uint8Array的api
    Buffer的实例 => auth字符串 (用于则表示编码字符的序列 UTF-8 Base64 十六进制)
Buffer的大小是一般来说的,在建立时就确定了,无法调整const buf1 = Buffer.alloc(10) // 建立两个宽度为10 填充为0的Buffer
        console.log(buf1) // <Buffer 00 00 00 00 00 00 00 00 00 00>
        const buf2 = Buffer.alloc(10,1) // 建立两个宽度为10 填充为1的Bufferconsole.log(buf2) // <Buffer 01 01 01 01 01 01 01 01 01 01 >
        const buf3 = Buffer.allocUnsafe(10) // 建立两个宽度为10, 速度比alloc快 但是建立的头文件里可能有旧统计数据
        console.log(buf3) // <Buffer d8 0b 01 06 00 00 00 00 08 da>
        
        const buf = Buffer.from(hellow world, ascii) // 参数1:生成文本 参数2:文本的编码方式
        console.log(but) // <Buffer 68 65 6c 6f 20 77 6f 72 6c 64>console.log(buf.toString(base64)) // …base64编码的字符串
        
    
    认知Streamshell透过管道连接各个部分,输入和输出的规范是文本流
    nodejs内置的Stream模块实现了类似的功能,各个部分之间透过pipe()连接
流中的统计数据默认情况下都是Buffer类别。产生的统计数据一放入流中,便转成Buffer被消耗;写入的统计数据在传给底层写逻辑时,也被转成Buffer类别。Stream.Readable 可读建立可读流时须要继承Readable并实现_read方法
_read方法是从底层系统读取具体文本统计数据的逻辑,即生产统计数据的逻辑。 在_read方法中,透过调用push(data)将统计数据放入可读流中供下游消耗。 在_read方法中,能同步调用push(data),也能异步调用。 当全部统计数据都生产出来后,必须调用push(null)来结束可读流。 流一旦结束,便不能再调用push(data)添加统计数据。const Readable = require(stream).Readable
        class ToReadable extends Readable {
        constructor(){
        super()
        this.iterator = iterator
        }
        _read(){
        const res = this.iterator.next()
        if(res.done){
        return this.push(null)
        }
        setTimeout(()=>{
        this.push(res.value)
        },0)
        }
        }
        const iterator = function(limit){
        return {
        next: function(){
        if(limit–){ return {done:false,value:limit+Math.random()} }
        return { done: true }
        }
        }
        }(10)
        const readable = new ToReadable(iterator)
        readable.on(data, data=>{process.stdout.write(data)})
        readaable.on(end, ()=>{process.stdout.write(DONE)})
    2. Stream.Writeable 可写
    Readable透过继承的方式去建立一类可读流,Writeable也适用于建立一类可写流,只是须要实现的是write(data, enc, next)方法,而不是read()方法
上游透过调用writable.write(data)将统计数据写入可写流中。write()方法会调用_write()将data写入底层。在_write中,当统计数据成功写入底层后,必须调用next(err)告诉流开始处理下两个统计数据。next的调用既能是同步的,也能是异步的。上游必须调用writable.end(data)来结束可写流,data是可选的。此后,不能再调用write新增统计数据。在end方法调用后,当所有底层的写操作方式均完成时,会触发finish事件。const Writable = require(stream).Writable
        const writable = Writable()
        // 实现`_write`方法
        // 这是将统计数据写入底层的逻辑
        writable._write = function (data, enc, next) {
        // 将流中的统计数据写入底层
         process.stdout.write(data.toString().toUpperCase())
        // 写入完成时,调用`next()`方法通知流传入下两个统计数据
         process.nextTick(next)
        }
        // 所有统计数据均已写入底层writable.on(finish, () => process.stdout.write(DONE))
        // 将两个统计数据写入流中
        writable.write(a + \n)
        writable.write(b + \n)
        writable.write(c + \n)
        // 再无统计数据写入流时,须要调用`end`方法
        writable.end()
    
    3. Stream.Duplex 可读可写
    Duplex实际上就是继承了Readable和Writable的一类流。 所以,两个Duplex第一类既可当成可读流来使用(须要实现read方法),也可当成可写流来使用(须要实现write方法)。
    var Duplex = require(stream).Duplex
        var duplex = Duplex()
        // 可读端底层读取逻辑
        duplex._read = function () {
        this._readNum = this._readNum || 0
        if (this._readNum > 1) {
        this.push(null)
        } else {
        this.push( + (this._readNum++))
        }
        }
        // 可写端底层写逻辑
        duplex._write = function (buf, enc, next) {
        // a, b
         process.stdout.write(_write  + buf.toString() + \n)
        next()
        }
        // 0, 1
        duplex.on(data, data => console.log(ondata, data.toString()))
        duplex.write(a)
        duplex.write(b)
        duplex.write(x)
        duplex.end()
    
    4. Stream.Transform 可读可写可变换
    Duplex的例子中,可读流中的统计数据(0, 1)与可写流中的统计数据(’a’, ‘b’)是隔离开的,但在Transform中可写端写入的统计数据经变换后会自动添加到可读端。 Tranform继承自Duplex,并已经实现了read和write方法,同时要求用户实现两个_transform方法。
    const Transform = require(stream).Transform
        class Rotate extends Transform {
        constructor(n) {
        super()
        // 将字母移动`n`个位置
         this.offset = (n || 13) % 26
        }
        // 将可写端写入的统计数据变换后添加到可读端 _transform(buf, enc, next) {
        var res = buf.toString().split().map(c => {
        var code = c.charCodeAt(0)
        if (c >= a && c <= z) {
        code += this.offset
        if (code > z.charCodeAt(0)) {
        code -= 26
        }
        } else if (c >= A && c <= Z) {
        code += this.offset
        if (code > Z.charCodeAt(0)) {
        code -= 26
        }
        }
        return String.fromCharCode(code)
        }).join()
        // 调用push方法将变换后的统计数据添加到可读端 this.push(res)
        // 调用next方法准备处理下两个
         next()
        }
        }
        var transform = new Rotate(3)
        transform.on(data, data => process.stdout.write(data))
        transform.write(hello, )
        transform.write(world!)
        transform.end()
    
    认知Eventsevents模块是node的核心模块之一,几乎所有常用的node模块都继承了events模块,比如http、fs等。
注册事件监听器前,事件先触发,则该事件会间接被忽略单个事件监听器// 事件触发时,事件监听器按照注册的顺序执行var EventEmitter = require(events);
        class Man extends EventEmitter {}
        var man = new Man();
        man.on(wakeup, function(){
        console.log(man has woken up);
        });
        man.emit(wakeup); // man has woken up
        
    
    2. 同个事件 多个事件监听器
    var EventEmitter = require(events);
        class Man extends EventEmitter {}
        var man = new Man();
        man.on(wakeup, function(){
        console.log(man has woken up);
        });
        man.on(wakeup, function(){
        console.log(man has woken up again);
        });
        man.emit(wakeup);
    
    3. 只运行一次的事件监听器
    var EventEmitter = require(events);
        class Man extends EventEmitter {}
        var man = new Man();
        man.on(wakeup, function(){
        console.log(man has woken up);
        });
        man.once(wakeup, function(){
        console.log(man has woken up again);
        });
        man.emit(wakeup);
        man.emit(wakeup);
        // 输出如下:
        // man has woken up
        // man has woken up again// man has woken up
        
    
    4. 移除事件监听
    var EventEmitter = require(events);
        function wakeup(){
        console.log(man has woken up);
        }
        class Man extends EventEmitter {}
        var man = new Man();
        man.on(wakeup, wakeup);
        man.emit(wakeup);
        man.removeListener(wakeup, wakeup);
        man.emit(wakeup);
        // 输出如下:
        // man has woken up
        
    
    node中的自上而下第一类Node.js 中的自上而下第一类是 global,所有自上而下变量(除了 global 本身以外)都是 global 第一类的属性。
    global 最根本的作用是作为自上而下变量的宿主
自上而下变量的定义:在最外层定义的变量;自上而下第一类的属性;隐式定义的变量(未定义间接赋值的变量)。// node中的this其实是module.exports
        console.log(this); // {}
        module.exports.foo = 5;
        console.log(this); // { foo:5 }
        
    
自上而下变量__filename__filename 则表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。 如果在模块中,返回的值是模块文件的路径。
    2. 自上而下变量__dirname
    __dirname 则表示当前执行脚本所在的目录。
    3. 自上而下方法 setTimeout(cb, ms), clearTimeout, setInterval, clearInterval, console,
    4. 自上而下变量 process
    用于描述当前Node.js 进程状态的第一类,提供了两个与操作方式系统的简单接口。
    // process 对象的一些最常用的成员方法
        // exit 当进程准备退出时触发。
        process.on(exit, function(code) {})
        // beforeExit
        当 node 清空事件循环,并且没有其它安排时触发这个事件。通常来说,当没有进程安排时 node 退出,但是 ‘beforeExit’ 的监听器能异步调用,这样 node 就会继续执行。
        process.on(beforeExit, function(code) {})
        // uncaughtException
        当两个异常冒泡回到事件循环,触发这个事件。如果给异常添加了监视器,默认的操作方式(打印堆栈跟踪信息并退出)就不会发生。
        process.on(uncaughtException, function(code) {})
        // Signal
        当进程接收到信号时就触发。信号列表详见标准的 POSIX 信号名,如 SIGINT、SIGUSR1 等。
        process.on(Signal, function(code) {})
        // 输出到终端
        process.stdout.write(“Hello World!” + “\n”);
        // 透过参数读取
        process.argv.forEach(function(val, index, array) {
        co       // 平台信息
        console.log(process.platform);
    补充
    1字节(byte)= 8位(bit)js中Number 64位 => 8bytenode中目前支持的字符编码 [ 7位的ascii统计数据 | 多字节编码的Unicode字符.html | base64 ]退出时的状态码Uncaught Fatal Exception 有未捕获异常,并且没有被域或 uncaughtException 处理函数处理。
    3 Internal JavaScript Parse Error JavaScript的源码启动 Node 进程时引起解析错误。非常罕见,仅会在开发 Node 时才会有。
    4 Internal JavaScript Evaluation Failure JavaScript 的源码启动 Node 进程,评估时返回函数失败。非常罕见,仅会在开发 Node 时才会有。
    5 Fatal Error V8 里致命的不可恢复的错误。通常会打印到 stderr ,文本为: FATAL ERROR
    6 Non-function Internal Exception Handler 未捕获异常,内部异常处理函数不知为何设置为on-function,并且不能被调用。
    7 Internal Exception Handler Run-Time Failure 未捕获的异常, 并且异常处理函数处理时自己抛出了异常。例如,如果 process.on(‘uncaughtException’) 或 domain.on(‘error’) 抛出了异常。
    9 Invalid Argument 可能是给了未知的参数,或者给的参数没有值。
    10 Internal JavaScript Run-Time Failure JavaScript的源码启动 Node 进程时抛出错误,非常罕见,仅会在开发 Node 时才会有。
12 Invalid Debug Argument 设置了参数–debug 和/或 –debug-brk,但是选择了错误端口。