node学习笔记

作者: liuxinya | 来源:发表于2018-03-15 17:03 被阅读0次

    node.js 介绍

    node.js初识

    1. node.js 平台是基于 Chrome V8 JavaScript 引擎构建。
    2. 基于 node.js 可以开发控制台程序(命令行程序、CLI程序)、桌面应用程序(GUI)(借助 node-webkit、electron 等框架实现)、Web 应用程序(网站)

    node.js 有哪些特点?

    1. 事件驱动(当事件被触发时,执行传递过去的回调函数)
    2. 非阻塞 I/O 模型(当执行I/O操作时,不会阻塞线程)
    3. 单线程
    4. 拥有世界最大的开源库生态系统 —— npm。

    事件循环(Event-Loop)

    事件循环会监视调用栈,以及回调队列
    如果调用栈中为空,这个时候,就会将回调队列中的第一个元素放到调用栈中调用

    异步-非阻塞

    js是单线程的 异步的功能是由webapi或者nodeapi提供的!!## 事件循环(Event-Loop)
    事件循环会监视调用栈,以及回调队列
    如果调用栈中为空,这个时候,就会将回调队列中的第一个元素放到调用栈中调用

    异步-非阻塞

    js是单线程的 异步的功能是由webapi或者nodeapi提供的!!

    进程和线程

    • 每一个 正在运行 的应用程序都称之为进程。
    • 每一个应用程序运行都至少有一个进程
    • 进程是用来给应用程序提供一个运行的环境
    • 进程是操作系统为应用程序分配资源的一个单位

    • 用来执行应用程序中的代码
    • 在一个进程内部,可以有很多的线程
    • 在一个线程内部,同时只可以干一件事
    • 而且传统的开发方式大部分都是 I/O 阻塞的
    • 所以需要多线程来更好的利用硬件资源

    Node 中将所有的阻塞操作交给了内部实现的线程池

    Node 本身主线程主要就是不断的往返调度

    REPL环境

    1. REPL 全称: Read-Eval-Print-Loop(交互式解释器)
    • R 读取 - 读取用户输入,解析输入了Javascript 数据结构并存储在内存中。
    • E 执行 - 执行输入的数据结构
    • P 打印 - 输出结果
    • L 循环 - 循环操作以上步骤直到用户两次按下 ctrl-c、.exit或者process.exit() 按钮退出。
    1. 在REPL中编写程序 (类似于浏览器开发人员工具中的控制台功能)
    • 直接在控制台输入 node 命令进入 REPL 环境
    1. 按两次 Control + C 退出REPL界面 或者 输入 .exit 退出 REPL 界面
    • 按住 control 键不要放开, 然后按两下 c 键

    node.js中JavaScript 文件名命名规则

    • 不要用中文
    • 不要包含空格
    • 不要出现node关键字
    • 建议以 '-' 分割单词

    node.js命令

    process.stdout.write

    这个方法可以用来输出内容,而且不会自动换行
    如果要换行可以加上\n

    fs模块--文件的读写

    var fs = require("fs"); // 引用fs模块
    // 写
    fs.writeFile("文件路径", "要写的内容", "编码格式", function(err){
        if(err){
            throw err;
        }
        console.log("写入成功")
    })
    // 读
    fs.readFile("文件路径", function(err, data){
        //data是一个Buffer 字节数组
        //获取字符串,需要自己toString
    })
    // 读
    fs.readFile("文件路径", "utf-8", function(err, data){
        //data是一个字符串
    })
    
    // 创建一个目录
    fs.mkdir('./test-mkdir',function(err){
        if(err){
            console.log("创建文件夹出错");
            console.log(err)
        }else{
            console.log("创建成功")
        }
    })
    

    path模块相关

    • __dirname -- 获取当前文件所在目录的完整路径(伪全局)

    • __filename -- 获取当前文件的完整路径 (伪全局)

    • path.join() -- 用来拼接路径

    
    path.join(__dirname,"css","index.css");
    
    

    http模块

    直接上代码

    //1. 引入http模块
    var http = require("http");
    
    // 2. 创建服务实例
    var server = http.createServer();
    
    // 3. 注册请求事件(每当有请求来的时候,就会触发该事件)
    server.on("request",function(request,response){
    
        // 设置响应头
        response.writeHead(200,"OK",{
            "Content-Type":"text/html;charset=utf-8"
        })
    
        //给浏览器端返回数据(要给响应体中添加内容)
        response.write("");
    
        //在所有的响应信息添加完毕之后,需要结束响应
        response.end(); 
    })
    
    //4. 开启服务实例的监听功能
    server.listen(端口号, function(){
        //监听开启成功后会执行的函数
        console.log("服务启动成功")
    })
    

    request对象

    • url 浏览器请求的地址(包含两部分 路径?参数)
    • method 浏览器发送该请求的方式 GET POST
    • headers 请求头中所有的信息(对象)
    • rawHeaders 请求头中所有的信息(数组)
    • httpVersion 请求头中包含的协议的版本

    response对象

    • response.setHeader("键", "值") 往请求头中新增信息

    • response.writeHead(状态码, 状态描述信息, {往请求头中新增信息的键值对})

      • setHeader和writeHead都可以用来设置响应头
      • writeHead是直接将内容写入响应头中,而setHeader是在end的时候才写入
      • 如果同时使用setHeader和writeHead设置了响应信息,那么会合并,如果有相同的内容则以writeHead的为主
    • response.write(data, "编码格式", callback) 给响应体中追加内容

    • response.end(data) 通知服务器 所有的响应内容已经发送完毕 如果传入了data,就相当于是先调用response.write将数据追加之后再response.end结束响应 每次响应都需要调用这个end方法

    • response.statusCode -- 设置状态码

    • response.statusMessage -- 设置状态码对应的状态信息

    mime (第三方模块)

    在页面请求的时候,不同的资源是有不同的content-type的值的,如果通过response.url一一匹配设置太麻烦了,可以通过 mime 模块设置不同类型资源的Content-Type

    • npm install mime
    • 在代码中直接引用 var mime = require('mime')
    server.on("request",function(request,response){
        if(request.url.startsWith("/static")){
            response.writeHead(200,"OK",{
                "Content-Type":mime.getType("文件路径")
            })
        }
    })
    

    获取post请求发送的数据

    如果post传过来的数据时大量的话,那么data事件可能会触发多次,所以可声明一个空数组,用来存放每次触发data事件的时候传过来的一段数据,end事件是当数据全部传送完毕的时候会调用的函数,这个时候再把数组中每一次传过来的数据拼接起来,就得到了完整的数据。

    
    server.on("request", function(req, res){
        var chunkArr = [];  // 用来保存post请求传过来的数据
        req.on("data", function(chunk){
            chunkArr.push(chunk);  // 将此次数据存放起来
        })
    
        req.on("end", function(){
            // 拼接全部数据
            var result = Buffer.concat(chunkArr);
        })
    })
    
    

    获取get请求发送的数据

    get请求的数据是在URL地址栏里的,所以可利用 url模块 或者 querystring 模块获取

    • url模块
        var url = require("url");
        var urlObj = url.parse(request.url,true); // 返回的是个对象,包含了url里面的信息
        urlObj.query  // query这个属性返回的是参数(也即是get方式的数据)对象
        
    

    underscore和arttemplate --node.js模板--第三方模块

    // underscore
    var _ = require("underscore");
    var render = _.template("模板字符串");
    var resultHtml = render("数据");
    response.end(resultHtml); // 发送给客户端 
    
    // arttemplate
    
    // 直接自己读文件
    var resultHtml = template("模板字符串",数据);
    
    // 根据模板字符串生成渲染函数
    var render = template.compile("模板字符串");
    var resultHtml = render(数据);
    

    node.js模块化

    • NOde采用的模块化结构是按照CommonJS规范

    • 模块与文件是意义对应关系,即加载一个模块,实际上就是加载该模块对应的模块文件

    • 模块特点

      • 所有代码都运行在模块作用域,不会污染全局作用域。
      • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
      • 模块加载的顺序,按照其在代码中出现的顺序。
    • 模块分类

      • 文件模块 -- 就是我们自己写的功能模块文件

      • 核心模块 -- Node 平台自带的一套基本的功能模块,也有人称之为 Node 平台的 API

      • 第三方模块 -- 社区或第三方个人开发好的功能模块,可以直接拿回来用

    1. 定义模块

    将代码写在一个js文件中,这个js文件就是一个模块了

    module.exports是一个对象,这个对象会在模块被创建出来的时候,同时被创建

    // module.exports.成员 = 内容;
    var say = function(){};
    module.exports.say = say;
    
    // 也可以直接给module.exports赋值
    module.exports = {
        say : say
    }
    
    // 注意: 虽然exports和module.exports指向的是同一个对象的的引用地址,但是模块暴露给外接的属性或方法,只能直接赋值给module.exports,因为模块最终的返回值是 module.exports
    

    2. 引用模块

    • 核心模块

      • require("核心模块名称")
    • 文件模块

      • require("文件的路径,必须以/ ./ ../开头")

      • 文件路径中的.js路径可以省略,如果省略 .js 则node会查找 以该文件为名字 以 .js .node .json 为后缀的文件来加载,如果没有,就报错了

    • 目录模块

      • require("目录路径,必须以/ ./ ../开头")

      • 当以目录路径为参数的时候node.js会查找该目录下的 package.json 文件,会加载其 main 属性所对应的文件

      • 如果没有 package.json 或者package.json中没有main属性 则去加载目录中 index.js index.node

    • node_modules中的模块

      • require("模块名称");

      • (这么写是不带./ / ../)

      • 如果这么写,先回去核心模块中查找,如果找不到,则去当前目录的父路径中的node_modules文件夹中查找对应的模块,如果还是找不到,就会一直沿着父路径往上找,直到找到硬盘根目录

      • 如何查看要查找的路径(module.paths)

    3. 删除模块缓存

     let absolutepath = path.join(__dirname, `../data/test.json`);
     delete require.cache[absolutepath];
     require(absolutepath);
    

    express

    express是什么

    express是一个简单高效用来开发web应用的框架(基于node.js)

    怎么用它

    1. 安装
    • npm install express -S
    1. 引用并使用
    //1. 引入
    var express = require("express");
    
    //2. 创建实例
    var app = express();
    
    //4. 注册路由
    app.use(express.static("static"))
    
    //3. 启动服务监听
    app.listen(8888,function(){
        console.log("http://localhost:8888")
    })
    

    express.static(root,[options])

    express 中的中间件

    • 中间件(Middleware) 是一个函数,它可以访问请求对象(request object (req)), 响应对象(response object (res)), 和 web 应用中处于请求-响应循环流程中的中间件,一般被命名为 next 的变量。

    • 常规中间件(应用级中间件)的回调函数,一般有3个参数

      • req, res, next
      • 其中next()是一个函数,通过这个函数把执行流程交给下一个中间件
    • 可以挂载中间件的部分方法

      • app.use()
      • app.get()、app.post()、app.put()、app.delete()、...等各种请求方法
      • 注意:在挂载中间件时 next() 方法的重要性,不调用该方法无法执行到下一个中间件
    • 中间件的应用场景

      • 利用中间件实现记录日志功能
      • 利用中间件模拟body-parser功能

    路由注册

    1. app.method
    // 只接受指定方式的请求
    app.get("/index",function(req,res){})
    
    app.post()
    
    1. app.use
    
    // 可以接受任意方式的请求
    // 请求路径pathname,必须以路由路径开头
    app.use("/index",function(req,res){})
    
    // index.html index/s/a  都可以
    
    1. app.all
    // 可以接受任意方式的请求
    // 请求路径pathname必须和路由路径完全一样
    app.all("/index",function(req,res){})
    
    // index/s/a 不可以
    

    res对象新增功能

    • res.send()

      • send可以将对象 字符串 数组 数字 等等数据返回给浏览器
      • 一次请求中只能用一次
      • 他里面自动给响应报文头中添加了一些内容 Content-type
    • res.sendFile()

      • 可以用来向浏览器发送文件内容
    • res.json

    • res.jsonp

    • res.status(状态码).end(""); -- 设置状态码

    • res.redirect('http://google.com'); -- 重定向

    req对象获取GET方式或POST方式的请求数据

    • req.query 直接就可以获取到get请求的参数对象

    • req.body 可以获得POST提交方式的请求数据内容,但是需要配置

      • 如果form表单中的enctype属性未设置或者设置为application/x-www-form-urlencoded,那么req.body就可以通过body-parser解析之后获取到请求数据
      • 但是如果设置为 multipart/form-data这样的格式 ,那么req.body是拿不到内容的!!
    • req.body的配置

      • 下载包 npm install body-parser -S
      • 引包 var parser = require("body-parser");
      • 将其挂载到app上 app.use(parser.urlencoded({extended: false}));
      • 注意: extend属性如果设置为true, 则express最终将数据转换成对象的时候使用的就是qs模块,如果是false则使用的是querystring模块!
      • 注意: 挂载use这局代码一定写在app.use(router)之上,先让parser处理POST请求的数据,然后再让路由去处理相关数据的逻辑代码
    // GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse
    req.query.order
    // => "desc
    
    var app = require('express')();
    var bodyParser = require('body-parser');
    var multer = require('multer'); 
    
    app.use(bodyParser.json()); // for parsing application/json
    app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
    app.use(multer()); // for parsing multipart/form-data
    
    app.post('/', function (req, res) {
      console.log(req.body);
      res.json(req.body);
    })
    

    路由对象

    // router.js文件中
    var express = require("express")
    var router = express.Router();
    
    router.get()
    router.use()
    
    // app.js文件中
    var app = express();
    app.use(router);
    

    nodemon 自动刷新应用

    1、全局下载 nodemon

    npm install -g nodemon
    

    2、 修改 package.json的 scripts

    {
      "name": "myapp",
      "version": "0.0.0",
      "private": true,
      "scripts": {
        "start": "nodemon ./bin/www"    // here here
      },
      "dependencies": {
        "cookie-parser": "~1.4.3",
        "debug": "~2.6.9",
        "express": "~4.16.0",
        "http-errors": "~1.6.2",
        "morgan": "~1.9.0",
        "pug": "2.0.0-beta11"
      }
    }
    
    

    模板引擎(集成在express中如何使用)

    var express = require("express");
    var app = express();
    
    // 1. 指定的为指定的后缀的模板文件,指定相应的模板引擎
    app.engine("html", require("express-art-template"));
    
    //2. 将模板的后缀通过set方法进行设置
    app.set('view engine', 'html');
    
    //3. 设置模板文件存放的目录
    app.set("views", "./views")
    
    app.get("/index", function(req, res){
        //res.render("不带后缀的模板文件的名称(这个文件会去设置好的模板文件的存放目录去查找)", {数据}, function(err, html){
            //err是异常信息
            //html 模板最终的渲染结果,最终生成的html代码
        // })
        res.render("index", {list: [{name: "呵呵"}, {name: "呵呵"}, {name: "哈哈"}]}, function(err, html){
            res.send(html);
        })
    })
    

    弹框下载

    1. node.js原生实现
    res.setHeader("Content-Type", "application/octet-stream")
    res.setHeader("Content-Disposition", "attachment; filename=xxx.txt")
    //要返回的文件内容,需要自己手动进行读取,通过res.write获取res.end返回给浏览器
    fs.readFile(path.join(__dirname, "xxx.js"),"utf-8", function(err, data){
        res.end(data);
    })
    
    1. express实现
    res.download("文件路径");
    

    使用node.js发送请求

    • 流程介绍

      • 引入http模块
      • 给http注册request事件
      • 设置请求参数
      • 获取响应信息(和用node.js原生代码,拿POST方式提交数据一样)
      • 注册 发生错误的事件
      • 结束请求
    • 代码示例

    var http = require("http");
    var req = http.request({
        host:"www.qiushibaike.com",
        hostname:"www.qiushibaike.com",
        method:"GET",
        port:443,
        path:"/",
        headers:{
            "Connection":" keep-alive",
            "Pragma":" no-cache",
            "Cache-Control":" no-cache",
            // 必须要写!!
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
            //注意:gzip如果在请求头中出现了,那么服务器端在响应请求的时候,会将所有的数据进行压缩,以提高传输效率
            //如果是浏览器在请求,那么浏览器拿到压缩后的数据之后,会自行解压,然后进行展示
            //nodejs中请求到数据之后,并不能自行解压,所以我们不在请求头加这个内容!
        }
    },function(response){
        var buffer = []; // 用来存放返回信息
        response.on("data",function(chunk){
            buffer.push(chunk);
        });
        response.on("end",function(){
            buffer = Buffer.concat(buffer);
            buffer.toString("utf-8")
        })
    })
    req.on("error", function(err){
        throw err;
    })
    // end事件不要忘记注册!
    req.end();
    

    cheerio 处理服务器返回来的HTML代码

    • 咋弄

      • 下载包 npm install cheerio -S
      • 引包 var cheerio = require("cheerio")
      • 加载返回回来HTML数据 var $ = cheerio.load("html代码")
      • 然后就和jQuery一样来操作里面的元素就阔以了!
    • 代码示例

    var cheerio = require("cheerio");
    // 通过http,拿到的HTML格式的数据经过buffer拼接,转码,发送给cheerio
    var $ = cheerio.load(Buffer.concat(buffer).toString("utf-8"));
    // 用来存放自己想要的东西
    var qiubaArr = [];   
    $(".article").each(function(index, ele){
        // 拿到所有author
        var author = $(ele).find(".author h2").text()
        var content = $(ele).find(".content>span").text();
        // 把所有数据存起来,然后
        qiubaArr.push({
            author,
            content
        })
    })
    

    CRUD


    使用 MongoDB 官方提供的 mongodb 驱动包操作 MongoDB 数据库

    安装:

    npm install mongodb --save
    

    CRUD:

    参考文档:

    var mongodb = require('mongodb')
    
    // 连接路径URL
    var url = 'mongodb://localhost:27017/itcast'
    
    var MongoClient = mongodb.MongoClient
    
    // ================== 插入数据 ==================
    // 1. 连接数据库(打开冰箱门)
    // MongoClient.connect(url, function (err, db) {
    //   if (err) {
    //     throw new Error('连接失败')
    //   }
    
    //   // 2. 把大象放到冰箱
    //   db.collection('heros').insert({ name: '张飞', gender: '男', age: 23 }, function (err, result) {
    //       if (err) {
    //         throw new Error('插入数据失败')
    //       }
    //       console.log(result)
    
    //       // 3. 关上冰箱门
    //       db.close()
    //     })
    // })
    // ================== /插入数据 ==================
    
    
    // ================== 查询数据 ==================
    // MongoClient.connect(url, function (err, db) {
    //   if (err) {
    //     throw new Error('连接失败')
    //   }
    
    //   // 查询所有
    //   // db.collection('heros').find({}).toArray(function (err, docs) {
    //   //   if (err) {
    //   //     throw new Error('查询数据失败')
    //   //   }
    //   //   console.log(docs)
    //   // })
    
    //   // 按条件查询
    //   db.collection('heros').find({name: '张飞'}).toArray(function (err, docs) {
    //     if (err) {
    //       throw new Error('查询数据失败')
    //     }
    //     console.log(docs)
    //   })
    // })
    // ================== /查询数据 ==================
    
    
    
    // ================== 更新数据 ==================
    // MongoClient.connect(url, function (err, db) {
    //   if (err) {
    //     throw new Error('连接失败')
    //   }
    //   db.collection('heros').updateOne({name: '张飞'}, {
    //     $set: {
    //       age: 20
    //     }
    //   }, function (err, result) {
    //     if (err) {
    //       throw new Error('更新失败')
    //     }
    //     console.log(result)
    //   })
    // })
    // ================== /更新数据 ==================
    
    
    // ================== 删除数据 ==================
    // MongoClient.connect(url, function (err, db) {
    //   if (err) {
    //     throw new Error('连接失败')
    //   }
    //   db.collection('heros').deleteOne({name: '张飞'}, function (err, result) {
    //     if (err) {
    //       throw new Error('删除失败')
    //     }
    //     console.log(result)
    //   })
    // })
    // ================== /删除数据 ==================
    

    在node做本地服务器的项目中,做到文件下载

    • 流的方式
    router.post('/:cubeId/download', function(req, res, next) {
        let fileName = 'file';
        // console.log(res)
        // console.log(req.body);
        // console.log(res.body.params);
        let currFilePath = path.join(__dirname,`../data/file.txt`);
        let f = fs.createReadStream(currFilePath);
        res.writeHead(200, {
            'Content-Type': 'application/force-download',
            'Content-Disposition': `attachment; filename=file.txt`
        });
        f.pipe(res);
    })
    

    相关文章

      网友评论

        本文标题:node学习笔记

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