从零到整学习nodejs

101 阅读11分钟

node整理

Node简介

 js是一个寄生式语言,node和浏览器一样,是js的运行环境,08年node出现之后可以让js在后端运行。  
 node是一个应用程序,需要安装。

node安装

  • 官网
  • 中国官网
    进入官网之后会有2个下载面板,左边是长期稳定的版本,右边是最新版本(不太稳定版本),推荐使用左边的版本。

如果是window的电脑推荐使用的是window installer(安装包版本),会直接帮忙安装环境变量。
环境变量:信号放大器(在控制台中(终端)调用软件必须在其文件夹下调用,有了全局变量就会扩大搜索的范围,可以不在当前软件的文件夹下调用) image.png

在node中运行js

严重声明:因为脱离了浏览器,所以没有DOM,和BOM,只有ECMAScript语法了。
consolesetTimeoutsetInterval都有,location,window,history,document,alert等对象没有了

1.Win键 +R 输入cmd 打开控制台(推荐使用)

命令行基础:
返回上一个文件:cd ../
补全:tab
清除cmd中的内容:cls
重启:ctrl+c

2.切换到当前文件的所在目录

如果不在同一个盘符下,【盘符:】可以切换到对应的盘符下

3.node空格【文件名demo.js】

nodejs特点

1.单线程

因为js是单线程的,node也是单线程的
多线程:PHP,Java,.net等多线程的规则,资源(money)消耗的多,来一个消耗一个,如果用node节省9/10的资源(money)

2.非阻塞I/0

I/0【输入输出流】:内存和磁盘之间的数据交换过程。
I:inputStream 输入流,指向内存中输入内容。
O:outputStream 输出流,指向内存中向外输出。
因为学node,搭建服务器,接收前端请求,当前端来请求文件的时候,服务器会从硬盘中读取目标文件到内存里,在把读取到的内容发给前端。从磁盘中读取内容到内存中,这个叫input输入,磁盘和内存传输数据以磁盘为准(以速度慢的为准),内存等着磁盘的传输叫做阻塞I/0,否则就叫做非阻塞I/0。

3.事件驱动

当磁盘与内存之间传递完毕数据之后,有后续任务,可是线程已经离开,没有办法立即执行,把后续任务以事件的形式传递给线程。

Node内置模块

Node内置模块变量

nodejs中内置的模块变量:require函数,exports对象,module对象,_dirname,_filename

node是CommonJS规范的实现之一。
模块化规范:CommonJS和AMD,CMD
异步模块化规范:AMD,CMD是前端模块化规范
同步模块化规范:CommonJS是后端模块化规范
commonJS用同步的方式加载模块。在服务端,模块文件都存在本地磁盘,读取非常快,
所以这样做不会有问题。但是在浏览器端,限于网络原因,更合理的方案是使用异步加载。
    // console.log(require)
    // console.log(exports)
    // console.log(module)
    // console.log(__dirname)
    // console.log(__filename)在js文件中书写,在控制台中输出,内容如下图

require函数:是一个函数 image.png

exports:是一个空对象,负责向外暴露内容 image.png

module:是一个模块对象,它身上具备当前模块的相关信息,重要的属性就一个exports,是一个空对象,负责向外暴露内容(exports和module.exports都负责向外暴露内容,以module.exports为准) image.png

__dirname:当前文件的绝对路径(不包含文件名) image.png

__filename:当前模块的绝对路径(包含文件名) image.png

如何定义一个模块

nodejs中一个JS文件就是一个模块

如何暴露模块内容

exports.xxx =function(){}
module.exports =function(){}
module.exports.xxx =function(){}
//切忌不能:exports=xxx???
为了方便,Node为每个模块提供一个 exports 变量,指向 module.exports。
这等同在每个模块头部,有一行这样的命令: var exports = module.exports
exports 被重新赋值了,不在指向module.exports

如何引用其他模块

1.引入核心模块
    require(核心名称字符串)
2.引入第三方模块
    如果第三方模块位于node_modules文件中,引入方式同上
    如果引入的第三方模块不在node_modules文件中,引入require(相对路径),相对路径必须从./开始

node_modules文件夹

该文件夹是固定的,用来存放第三方模块,如果存在在该文件夹下,引用模块的时候,不需要书写相对路径直接写模块的名称即可
该文件夹可以放在当前层级,上层级和上上层级直到根目录,必须是直接层级

http模块(用来搭建服务器)

var http =require('http')
// 创建服务器
var server =http.createServer(function(req,res){
    //这个函数用于访问前端请求
    //req:request 前端发送的请求对象
    //res:response 后端操作对象
    console.log(req.url)//url字符串,从端口后面开始算,协议/域名/端口号/hash没有
    res.end('i love you zhoujun')
})
//监听到端口
// server.listen(3000)//这种监听方式,既可以通过IP地址访问,也可以通过localhost访问,也可以通过127.0.0.1访问(自己本身)
server.listen(3000,'192.168.31.232')//因为有第二个参数,只能用IP地址去访问

Fs模块(文件文件夹操作)

每一个方法都有对应的同步方法(读取完文件之后在进行下一步操作),方法名就是每个方法后面加Sync  
//引入fs模块
var fs =require('fs')
const data =fs.readFileSync('./aaa/a.txt')
console.log(data.toString())
console.log(1)

1.读取文件

//引入fs模块
var fs =require('fs')
fs.readFile('./a.txt',function(err,data){
//同步读取文件fs.readFileSync
    console.log(err,data.toString())
})
readFile接收2个参数,第1个参数是读取文件的路径,第二个参数是回调函数,
回调函数接收2个参数
err:在读取文件过程中可能出现的错误,如果没有发生错误,显示null
data:表示读取到的内容,前提是没有错误发生,如果有错误发生,data为undifined

2.追加文件

//引入fs模块
var fs =require('fs')
fs.appendFile('./d.txt','白敬亭是我的',function(err){
    // 接收3个参数,第一个参数是文件路径,第二个参数是追加内容,第三个参数是回调函数
    console.log(err)
})

3.删除文件

//引入fs模块
var fs =require('fs')
fs.unlink('./d.txt',function(err){
    // 接收2个参数,第一个参数是文件路径,第二个参数是回调函数(err)
    console.log(err)
})

4.创建文件夹

//引入fs模块
var fs =require('fs')
fs.mkdir('bbb',function(err){
    // 接收2个参数,第一个参数是文件路径,第二个参数是回调函数(err)
    console.log(err)
})

5.删除文件夹(只能删除空目录的文件夹)

//引入fs模块
var fs =require('fs')
fs.rmdir('bbb',function(err){
    // 接收3个参数,第一个参数是文件路径,第三个参数是回调函数(err)
    console.log(err)
})

6.读取文件夹

//引入fs模块
var fs =require('fs')
fs.readdir('bbb',function(err,arr){
    // 接收2个参数,第一个参数是文件路径,第二个参数是回调函数 (err,arr)
    //err:读取过程中可能发生的错误
    //arr:读取到文件夹中每一个文件和子文件夹组成的数组
    console.log(err)
})

6.判定目标状态

//引入fs模块
var fs =require('fs')
fs.stat('./aaa',function(err,stat){
    // 接收2个参数,第一个参数是文件路径,第二个参数是回调函数
    // 回调函数接收2个参数 
    //err:判定过程中可能发生的错误 stat:isDirectory()返回来布尔值,true表示文件夹,false表示文件
    console.log(err,stat.isDirectory())
})

http静态服务器

var http = require("http"); //搭建http服务
var fs = require("fs"); //对文件和文件夹进行修改
var url = require("url");

//创建服务器
var server = http.createServer(function (req, res) {
  //获取前端访问的url字符串
  var str = req.url; //获取的url是单斜杠开头,读取的是盘符根目录,需要改成相对路径
  //通过url模块对str进行处理
  var urlobj = url.parse(str);
  console.log(urlobj);
  fs.readFile("./web" + urlobj.pathname, function (err, data) {
    if (err) {
      //err是对象,说明读取过程出错了
      res.setHeader("content-type", "text/plain;charset=utf-8");//解决乱码
      res.end("404资源不存在");
      return;
    }
    // console.log(err,data)
    res.end(data);
  });
});
server.listen(3000);
//1.如果获取的是文件中没有的web/index.html?a=1这个文件咋办
//解答:通过url模块对str进行处理,取urlobj.pathname
//2.如果获取的就是不存在的页面 =>res.end()会有乱码
//解答:res.setHeader('content-type','text/plain;charset=utf-8')
//3.http://localhost:3000/web/index.html=>http://localhost:3000/index.html去掉多余层级
//解答:fs.readFile('./web'+urlobj.pathname,function(err,data){}

http动态服务器(get和post)

html文件

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="../css/bootstrap.css">
</head>

<body>
    <h1>我是一个Node服务器</h1>
    <div class="container">
        <div class="row">
            <form class="form-inline" action="/regist" method="post">
                <div class="form-group">
                    <label for="exampleInputName2">用户名</label>
                    <input type="text" class="form-control" name="username" id="username" placeholder="username" >
                </div>
                <div class="form-group">
                    <label for="exampleInputEmail2">密码</label>
                    <input type="password" class="form-control" name="password" id="password" placeholder="password">
                </div>
                <textarea name="intro"></textarea>
                <button type="submit" class="btn btn-default">注册</button>
            </form>
        </div>
    </div>
    <script src="../js/jquery.min.js"></script>
    <script>
        var $username = $("#username");

        $username.blur(function() {
            $.ajax({
                url: "/checkusername", 
                data: {
                    username: $(this).val() // val方法 返回的是选中的元素的value值 如果有参数就是设置 
                },
                type: "get",
                dataType: "json",
                success: function(data) {
                    console.log(data);
                }
            });
        });
        


    </script>
</body>

</html>

server.js

var http = require("http");
var fs = require("fs");
var url = require("url");
//引入querystring模块对post请求参数进行处理
var qs = require('querystring')
var arr = [
  { username: "wanglaowu", password: "123456" },
  { username: "wanglaowu1", password: "123456" },
  { username: "wanglaowu2", password: "123456" },
  { username: "wanglaowu3", password: "123456" },
  { username: "wanglaowu4", password: "123456" },
];
var server = http.createServer(function (req, res) {
  //url.parse通过url模块将字符串处理下,接收2个参数,
  // 第一个参数是要处理的url字符串,第二个参数是布尔值true
  // 如果第二个参数为true,url对象的query是一个json格式的对象,否则是query是一个字符串
  const urlpath = url.parse(req.url, true);
  //处理动态资源------------------------------------------------get
  if (
    urlpath.pathname === "/checkusername" &&
    req.method.toUpperCase() === "GET"
  ) {
    var urlQueryUserName = urlpath.query.username;
    // console.log("检测是是否有用户名为" + urlQueryUserName + "的信息");
    //检测数组中的uername属性值为用户传递的值,result如果为真说明已经存在,为假说明不存在
    var result = arr.some((item) => item.username === urlQueryUserName);
    if (result) {
      res.setHeader("content-type", "text/plain;charset=utf-8");
      //res.end只接收string或者buffer
      //JSON.parse:字符串转对象
      // JSON.stringify:对象转字符串
      res.end(
        JSON.stringify({
          error: 1,
          msg: "用户名已经被占用",
        })
      );
      return;
    }
    res.setHeader("content-type", "text/plain;charset=utf-8");
    res.end(
      JSON.stringify({
        error: 0,
        msg: "可以使用",
      })
    );
    return;
  }
   //处理动态资源------------------------------------------------post
  if(urlpath.pathname === "/regist" &&
  req.method.toUpperCase() === "POST"){
    //post请求的数据在请求正文中,请求数据可能很大也可能很小,node为了统一处理,提供了两个事件(data事件,end事件都是req事件)
    // 1.data事件:传递一次数据触发一次,可能触发多次
    // 2.end事件:所有数据都触发完毕触发一次,end事件只能触发一次
    var str=''
    req.on('data',function(data_chunk){
        console.log('data事件触发一次')
        str += data_chunk
    })
    req.on('end',function(){
        console.log('end事件触发一次')
        var queryObj =qs.parse(str)
        console.log(queryObj)
        var useInfo ={
            username:queryObj.username,
            password:queryObj.password
        }
        arr.push(useInfo)
    })
    return
  }
  //处理静态资源------------------------------------------------
  fs.readFile("." + urlpath.pathname, function (err, data) {
    if (err) {
      res.setHeader("content-type", "text/plain;charset=utf-8");
      res.end("404资源不存在");
      return;
    }
    console.log(err);
    res.end(data);
  });
});
server.listen(3000);

npm 官网

npm是node自带的一个程序,用于管理所有的第三方模块.

常用命令:
安装模块                       npm install 模块名称  
初始化package.json文件          npm init  
根据package.json文件安装模块     npm install  
查看版本                        npm -v  
清除缓存                        npm cache clean ==force

express(node搭建服务器的一个框架)官网

下载express:npm install express
//引入express方法
var express = require("express");
//创建一个服务器
var server = express();
server.get("/", function (req, res) {
  //获取get请求的参数 req.query直接获取的是对象
  console.log(req.query);
  res.send("你好,美好的世界");
});
server.get("/aa", function (req, res) {
//res.send()可以接受对象,res.end()只接受beffer和字符串
  res.send({
    err: 0,
    data: "sucess",
  });
});
//监听端口号
server.listen(3000);

node压缩代码

Sass

 Sass是一个css预编译语言。(预编译:编译之前不是css,编译之后才是css)   
 为什么需要Sass?
 因为在书写的以后有很多不好的问题:  权重问题,以及样式复用(风格统一)问题。
 ```scss写```
 .header{
   .eyes
   }
 }
 
 ```通过node编译生成对应的css```
 .header{
 }
 .header .eyes{
 }
安装:安装sass到node全局:npm isntall sass -g  
作用:安装sass之后可以使用sass的指令,sass文件有2个后缀名:sass,scss 推荐使用 scss  
编译方式:sass 要编译的scss文件 要生成的css文件

Sass语法:

1.定义变量: $a:10px 等价于 var a ="10px"
2. &: 在样式列表中,表示当前选择器
//scss
.header{
    &:hover{
    }
}
//css
.header{
}
.header:hover{
}
3.定义混合:可以复用一组定义好的样式
  @mixin 混合名称{
        样式列表
  }
  使用混合:
  .header{
      @include 混合名称
  }
4.方法(混合与方法唯一的不同就是方法可以传递参数)
  //方法的参数默认值:与es6一样,如果传递了参数,使用传递的数值,如果没有传递参数,使用参数默认值
  @mixin method($a:100px,$b:300px,$c:yellow){
      width:$a,
      height:$b,
      background-color:$c
  }
  .header{
      @include method(100px,200px,red)
      .eye{
         @include method()
      }
  }
5.if语句
@mixin method($a,$b,$c:pink){
      width:$a,
      height:$b,
      @if($a>500px){
      background-color:red
      }@else if(($a>400px){
      background-color:blue
      }else{
       background-color:$c
      }
  }
  .header{
      @include method()
      .eye{
         @include method(501px,400px)
      }
  }
6.for语句
1.语法1
//定义一个变量从0循环到11
 @for $i from 0 to 12{
     
 }
2.语法2
//定义一个变量从0循环到12
 @for $i from 0 through 12{
     
 }
3.插值语法
@for $i from 0 through 12{
     .col-lg-#{$i}{
       width:percentage($i/12)
     }
 }
 //percentage用于将数字转化为百分比的方法
7.while语句
 $i =0
 @while $i<12{
   .col-#{$1}{
       width:percentage($i/12)
   }
   $i= $i+1
 }
8.引入sass文件
@import "./common/scss"

gulp

gulp是一个NodeJS的第三方模块
gulp是一个工程化工具,可以将我们书写的代码进行编译,压缩,合并,重命名等。
gulp有许多版本,我学习的是3.9.1

下载2次

npm install gulp@3.9.1 -g 安装到全局
npm install gulp@3.9.1 安装到本地(通常是指你要工程化操作的根目录) gulp -v 查看是否有下载成功 环境变量和本地的版本要一致 CLI (环境变量中的版本)
Local (本地中的版本)

书写配置文件 gulpfile.js

var gulp = require('gulp')
//调用gulp方法,定义任务
gulp.task('defalut',function(){
   //gulp是一个函数式编程的模块
   gulp.src('./origin/*')
   //对选中的资源如何处理放在管道pipe中
   .pipe(gulp.dest("./publish"))
})
gulp中自带的API
1.gulp.task(taskName,concent)
    taskName:可以是字符串  
    concent:可以是函数也可以是数组
    数组:数字中的每一个成员都必须是其他任务的名称
    函数:执行函数体中的代码

2.gulp.src(path)用于定位想要选择文件或文件夹
    path:路径字符串 
    可以用*代替所有目录(对于第一层来说) **代表所有目录和文件

3.gulp.src().pipe() 设置如何操作选中的文件或者文件夹
    pipe()可以链式打点调用 :gulp.src().pipe().pipe().pipe().pipe()

4.gulp.dest() 这个方法是`具体的操作`,表示发布到哪里去,
    参数是发布的路径字符串,如果字符串所指向的路径存在,则使用,如果不存在先创建在使用。

5.gulp.watch()两个参数
    第一个参数:任务名称,可以是数组
    第二个参数:要执行的任务名称组成的数组 也可以是函数
    gulp.task('a',funtion(){
        gulp.src('./origin/**')
        .pipe(gulp.dest("./publish"))
    })
    gulp.watch('./origin/**',['a'])
 ⚠️注意事项!!!
 真正写代码的时候遇到:primordials is not defined
 node版本号12及以上 ===>node降级到11.15.0版本
 Gulp使用v3.9.1

使用插件编译js文件

var gulp = require('gulp')
//引入压缩插件
var uglify = require('gulp-uglify')
gulp.task('js',funtion(){
    gulp.src('./origin/*.js')
    .pipe(uglify())
    .pipe(gulp.dest('./publish'))
})
gulp.task('defalut',['js'])

使用插件编译css文件

var gulp = require('gulp')
//引入压缩插件
var cssmin = require('gulp-cssmin')
gulp.task('css',funtion(){
    gulp.src('./origin/*.css')
    .pipe(cssmin())
    .pipe(gulp.dest('./publish'))
})
gulp.task('defalut',['css'])

添加css前缀

插件名称:gulp-autoprefixer
需要在package.json中配置:
 "browserlist":[
    "last 2 versions",
    "iOs > 7",
    "Firefox > 14"
  ]
 
了解了下package.json 与 package-lock.json的区别:
`package.json`记录的是当前项目中你下载了哪些包(也即`npm install xx` 的包信息),
记录了你下载的包信息(地址、版本号等),不包含依赖包信息。

`package-lock.json`文件记录的是当前项目中你下载了哪些包以及你下载的这些包的各种依赖包信息,包括地址、版本号等。主要作用有以下两点:
-   当删除node_module目录时,想通过`npm install `恢复所有包时,提升下载速度。
-   锁定版本号,防止自动升级新版本

转换es6==>es5(因为兼容性问题所以需要转换)

插件名称:gulp-babel@7.0.1
    + babel-core
    + babel-preset-es2015/babel-preset-env
    
var gulp = require("gulp");
var babel = require("gulp-babel");
gulp.task("babel", function () {
  gulp
    .src("./origin/js/animate.js")
    .pipe(
      babel({
        presets: ["es2015"],
      })
    )
    .pipe(gulp.dest("./publish08/js"));
});
gulp.task("default", ["babel"]);

处理HTML

插件名称:gulp-htmlmin
var gulp = require("gulp");
const htmlmin = require("gulp-htmlmin");
var babel = require("gulp-htmlmin");
gulp.task("htmlmin", function () {
  gulp
    .src("./origin/html/index.html")
    .pipe(
      htmlmin({
        collapseWhitespace: true, //删除空白
      })
    )
    .pipe(gulp.dest("./publish/js"));
});
gulp.task("default", ["htmlmin"]);

处理sass任务

插件名称:gulp-sass
var gulp = require("gulp");
const sass = require("gulp-sass")(require("sass"));
gulp.task("sassfuntion", function () {
  gulp.src("./origin/css/*.scss").pipe(sass()).pipe(gulp.dest("./publish/css"));
});
gulp.task("default", ["sassfuntion"]);

清除文件

插件名称:gulp-clean
按照顺序执行插件:gulp-sequence
var gulp = require("gulp");
var sass = require("gulp-sass")(require("sass"));
var clean = require("gulp-clean");
var sequence = require("gulp-sequence");
gulp.task("clean", function () {
  console.log(1);
  gulp.src("./publish/**").pipe(clean());
});
gulp.task("sassfuntion", function () {
  console.log(2);
  gulp.src("./origin/css/*.scss").pipe(sass()).pipe(gulp.dest("./publish/css"));
});
gulp.task("default", sequence("clean", "sassfuntion"));

启动自动打开文件

插件名称:gulp-webserver
var gulp = require("gulp");
var webserver = require("gulp-webserver");
gulp.task("webserver", function () {
  gulp.src("./publish").pipe(
    webserver({
      host: "localhost",
      post: 3000,
      open: "./index.html",
      fallback: "./publish/html/index.html",
      livereload: true,
    })
  );
});
gulp.task("publish", function () {
  gulp.src("./origin/**").pipe(gulp.dest("./publish/"));
});

gulp.task("default", ["webserver"]);