美文网首页
nodejs基础

nodejs基础

作者: wuww | 来源:发表于2018-05-08 10:25 被阅读65次

    Buffer: 处理二进制数据

    二进制数据的获取

    • 文件数据
    • 网络数据

    二进制数据的可读性:base64

    Base64是一种基于64个可打印字符来表示二进制数据的方法。

    转换前 11111111,11111111,11111111

    转换后 00111111, 00111111, 00111111, 00111111

    十进制 63 63 63 63

    对应码表中的值 ////

    图片
    let buf = Buffer.alloc(3, 0xff)
    
    /* 输出 //// */
    console.log(
        buf.toString('base64')
    )
    

    二进制数据的显示

    显示成base64
    buffer.toString('base64')
    
    显示成utf8编码的字符串
    buffer.toString('utf8')
    
    显示成16进制
    buffer.toString('hex')
    

    创建自定义Buffer

    通过utf8编码的字符串创建
    Buffer.from('text', 'utf8')
    
    通过base64创建
    Buffer.from('MTIz', 'base64')
    
    生成并初始化一个Buffer
    Buffer.alloc(3, 0xff)
    
    数据格式转换

    实现16进制、base64、utf8的自由转换

    Buffer.from('text', 'utf8').toString('base64')
    

    Stream

    Writable 可写流

    向目标写入数据

    图片
    const fs = require('fs')
    
    let writable = fs.createWriteStream('./log')
    
    writable.write('some text\n')
    writable.end('end\n')
    

    注意:如果写入数据时,writable.write(data)返回false说明缓冲区已满,需要等待drain事件触发后,再继续写入。

    Readable 可读流

    从目标读取数据

    两种读取数据的模式

    主动读取
    图片

    注意:缓冲区数据为空时readable.read()会返回null,建议配合readable事件表示。

    被动接收

    只要缓冲区中存在数据,就会触发data事件

    const fs = require('fs')
    
    let readable = fs.createReadStream('./log')
    
    let bufs = []
    
    // 绑定data事件后,流对象才会触发该事件
    readable.on('data', buf => {
        bufs.push(buf)
    })
    
    readable.on('end', () => {
        console.log(Buffer.concat(bufs).toString())
    })
    

    pipe

    连接可读流和可写流

    const http = require('http')
    const fs = require('fs')
    
    http.createServer((req, res) => {
        fs.createReadStream('./index.html').pipe(res)
    }).listen(3001)
    
    

    Duplex and Transform Streams

    图片
    gulp.src('client/templates/*.jade')
      .pipe(jade())
      .pipe(minify())
      .pipe(gulp.dest('build/minified_templates'));
    

    http模块

    发送请求

    const http = require('http')
    
    // 可写流
    let writable = http.request({
        protocol: 'http:',
        host: 'localhost',
        method: 'POST',
        headers: {
            'content-type': 'application/json'
        },
        path: '/test.json'
    }, onResponse)
    
    // 与请求头中的数据类型保持一致
    writable.write(
        JSON.stringify({
            a: 1,
            b: 2
        })
    )
    
    // 结束流
    writable.end()
    
    /**
     * @param {Stream.Readable} readable
     */
    function onResponse (readable) {
        let bufs = []
        readable.on('data', buf => {
            // 不能转成字符
            bufs.push(buf)
        })
    
        readable.on('end', () => {
            console.log(Buffer.concat(bufs).toString())
        })
    }
    

    http服务器

    const http = require('http')
    
    const server = http.createServer((readable, writable) => {
    
        // 从readable中获取数据
    
        writable.writeHead(200, {
            'content-type': 'application/json'
        })
    
        writable.write(
            JSON.stringify({
                code: 200,
                msg: 'success'
            })
        )
        writable.end()
    })
    
    server.listen(3001)
    

    bigpipe

    可以让浏览器在请求完全结束前提前开始页面渲染

    const http = require('http')
    
    const server = http.createServer(async (readable, writable) => {
    
        writable.writeHead(200, {
            'content-type': 'text/html'
        })
    
        await sleep(1000)
        writable.write('<div>a</div>')
    
        await sleep(1000)
        writable.write('<div>b</div>')
    
        await sleep(1000)
        writable.write('<div>c</div>')
    
        writable.end()
    })
    
    server.listen(3001)
    
    function sleep (ms) {
        return new Promise(resolve => {
            setTimeout(() => resolve(), ms)
        })
    }
    

    express

    每个中间件是一个函数。

    每个到达服务器的请求都会交给声明的中间件依次处理。

    每个中间件都可以选择直接向客户端返回数据或是将请求继续交给下一个中间件处理。

    图片
    const express = require('express')
    
    const app = express()
    
    app.use((req, res, next) => {
        console.log(req.originalUrl)
        next()
    })
    
    app.use((req, res, next) => {
        res.writeHead(200, {
            'content-type': 'text/html'
        })
        res.write('<div>hello world</div>')
        res.end()
    })
    
    app.use((req, res) => {
        console.log('不会执行')
    })
    
    app.listen(3001)
    

    koa

    每个中间件都可以选择直接返回上一个中间件或是将请求继续交给下一个中间件处理。

    图片
    const Koa = require('koa')
    
    const app = new Koa()
    
    app.use(async (ctx, next) => {
        let start = Date.now()
        await next()
    
        console.log(`${ctx.request.url}:${Date.now() - start}ms`)
    })
    
    app.use(async (ctx, next) => {
        ctx.response.status = 200
        ctx.response.headers['content-type'] = 'text/html'
        await sleep(1000)
        ctx.body = 'hello world'
    })
    
    app.use(async (ctx, next) => {
        console.log('不会执行')
    })
    
    app.listen(3001)
    
    function sleep(ms) {
        return new Promise(resolve => {
            setTimeout(() => resolve(), ms)
        })
    }
    

    常用中间件

    为服务器增加静态资源访问和缓存的能力
    File Serving

    解析HTTP请求体中的数据
    Body Parsing

    日志记录
    Logging

    多进程

    单个nodejs进程无法有效利用多核CPU

    // index.js
    
    const cp = require('child_process')
    
    for (let i = 0; i < 5; i++) {
        
        let ins = cp.fork('./sub.js')
    
        ins.on('message', msg => {
            console.log('master get message: ' + JSON.stringify(msg))
        })
    
        ins.send({
            text: 'message sent by master'
        })
    }
    
    // sub.js
    
    console.log('sub: ' + process.pid)
    
    process.on('message', msg => {
        console.log('sub get message: ' + JSON.stringify(msg))
    
        process.send({
            text: 'message sent by ' + process.pid
        })
    
    })
    
    

    cluster

    解决的问题:多个nodejs无法监听同一个端口。

    模块实现了多个进程同时监听同一个端口的功能。

    const cluster = require('cluster');
    const http = require('http');
    const numCPUs = require('os').cpus().length;
    
    if (cluster.isMaster) {
      console.log(`Master ${process.pid} is running`);
    
      // Fork workers.
      for (let i = 0; i < numCPUs; i++) {
        cluster.fork();
      }
    
      cluster.on('exit', (worker, code, signal) => {
        console.log(`worker ${worker.process.pid} died`);
      });
    } else {
      // Workers can share any TCP connection
      // In this case it is an HTTP server
      http.createServer((req, res) => {
        res.writeHead(200);
        res.end('hello world\n');
      }).listen(8000);
    
      console.log(`Worker ${process.pid} started`);
    }
    

    pm2

    多进程管理

    根据服务器CPU的核数启动多个实例

    实例意外退出时会自动重启实例

    $ pm2 start index.js -i -1

    进程监控

    $ pm2 monit

    图片

    开发模式

    $ pm2 start index.js --watch

    部署

    提供远程部署nodejs服务器的功能。

    pm2 通过ssh登录远程服务器,执行部署操作。

    /* deploy.json*/
    {
        "apps": [
            {
                "name": "server",
                "script": "index.js",
                "instances": 1,
                "exec_mode": "cluster"
            }
        ],
        "deploy": {
            "server1": {
                "user": "root",
                "host": [
                    "127.0.0.1"
                ],
                "ref": "origin/master",
                "repo": "https://github.com/user/project.git",
                "path": "/root/code",
                "post-deploy": "git pull && yarn && pm2 startOrRestart deploy.json",
                "pre-setup": "rm -rf /root/code"
            }
        }
    }
    

    第一次部署,pm2 会执行pre-setup,删除指定目录

    pm2 deploy deploy.json server1 setup

    再次部署,pm2 会执行post-deploy,从git拉取最新代码、安装依赖、重新启动程序

    pm2 deploy deploy.json server1

    eggjs

    eggjs

    继承自Koa, 增加了一组目录规范和一些常见问题的解决方案,包括应用部署、定时任务、日志、单元测试、CSRF防御、数据库操作等。

    多进程模型

    图片

    服务器性能

    wrk

    一个http压测工具

    Mac中安装方式:brew install wrk

    8个线程、建立200个连接,连续请求30s

    $ wrk -t8 -c200 -d30s --latency "http://localhost:3001"

    测试服务器在一段时间内持续接收到大量请求时的延迟情况。

    图片

    相关文章

      网友评论

          本文标题:nodejs基础

          本文链接:https://www.haomeiwen.com/subject/rjsirftx.html