node学习1:系统模块、第三方模块、gulp、http、异步编程

node学习1:系统模块、第三方模块、gulp、http、异步编程

一、node入门

服务端要做的事:
1.实现网站的业务逻辑
2.数据的增删改查

node是一个基于Chrome V8引擎的JavaScript代码运行环境

node.js运行环境安装:
官网:https://nodejs.org/en/

环境变量:如果想要在命令行中运行node,那就要确认node.exe 的path已经存储在环境变量中

在这里插入图片描述
基本使用:
可以使用cmd也可以用powershell
在这里插入图片描述
在这里插入图片描述
在文件目录下按shift+右键可以打开powershell
在这里插入图片描述
按clear可以清空内容

二、Node.js模块化开发

在这里插入图片描述
模块化开发的优点:可以抽离而不影响他人
在这里插入图片描述
例如:
a.js

const add = (n1, n2) => n1 + n2;
exports.add = add; //或者module.exports.add = add;

b.js

const a = require("./a.js");
console.log(a.add(10, 20)); //30

注意:exportsmodule.exports的别名,地址引用关系相同,当地址引用发生改变时,以module.exports为准

三、系统模块

node运行环境提供的API,因为这些API都是以模块化的方式进行开发的,所以我们又称node运行环境提供的API为系统模块
文件模块(fs):读取文件api、写入文件api、创建文件夹api

1. 文件操作

const fs = require('fs');
读取文件内容:fs.readFile('文件路径/文件名称' [, '文件编码'], callback);

//1. 通过模块的名字fs对模块进行引入
const fs = require('fs');
//2. 通过readFile读取文件
fs.readFile('./a.js', 'utf-8', (err, doc) => {
    console.log(err); //错误信息,成功读取则为null
    console.log(doc); //文件内容
});

写入文件内容:fs.writeFile('文件路径/文件名称' , '数据', callback); 会把原来的内容覆盖掉,没有文件则创建文件

const fs = require('fs');
fs.writeFile('./a.js', '写入的内容', err => {
    if (err != null) {
        console.log(err);
        return;
    }
    console.log('文件写入成功');
})

2. 路径操作

const path = require('path');
路径拼接:path.join('路径', '路径', ...)

// public/uploads/avater
const path = require('path');
const finalPath = path.join('public', 'uploads', 'avater');
console.log(finalPath); //public\uploads\avater

可以使用__dirname 获取当前文件所在的绝对路径
const absolutePath = path.join(__dirname, 'a.js');

四、第三方模块

别人写好的、具有特定功能的、我们能直接使用的模块就是第三方模块
有两种形式:
1.以js文件的形式存在,提供实现项目具体功能的api接口
2.以命令行工具形式存在,辅助项目开发

npm:node的第三方模块管理工具
下载:npm install 模块名称
卸载:npm uninstall 模块名称
命令行工具:全局安装
库文件:本地安装

1. 第三方模块nodemon

在这里插入图片描述
有了这个第三方模块,我们就可以一边更新代码一边看到输出,而不用每次都重新执行
按ctrl + c 退出

2. 第三方模块nrm

在这里插入图片描述
npm install nrm -g 下载nrm
nrm ls 查看可用下载地址
nrm use taobao 换到阿里提供的下载地址

另外:nrm ls报错:
在这里插入图片描述
修改:
在这里插入图片描述

参考:nrm ls报错解决方案

3. 第三方模块gulp

基于node平台开发的前端构建工具
将机械化的操作编写成任务,只需要一个命令行命令任务就能自动执行了,能够提高开发效率
譬如:
在这里插入图片描述

(1)gulp的基本使用

在这里插入图片描述
gulp中提供的方法
gulp.task(任务名字, 回调函数):建立gulp任务
gulp.src():获取任务要处理的文件
gulp.dest():输出文件
gulp.watch():监控文件的变化

gulpfile.js文件

// 引用gulp模块
const gulp = require('gulp');
// 使用gulp.task建立任务
gulp.task('first', done => {
    console.log('第一个gulp任务');
    //1. 使用gulp.src获取要处理的文件
    gulp.src('./src/css/normalize.css').pipe(gulp.dest('dist/css')); //仅仅完成了复制功能
    done();
});

运行(powershell):
npm install gulp-cli -g (安装gulp命令行命令)
gulp first (执行任务)
在这里插入图片描述
在这里插入图片描述

报错:gulp: Did you forget to signal async completion报错问题处理方案

(2)gulp插件

常用插件:
gulp-htmlmin:html文件压缩
gulp-csso:压缩css
gulp-babel:es6转换成es5
gulp-less:less转换成css
gulp-uglify:压缩混淆JavaScript
gulp-file-include:公共文件包含
browsersync:浏览器实时同步
文档:https://www.npmjs.com/
使用:下载插件;在gulpfile.js中引入插件;调用插件

例子

a. html任务:抽取公共代码+压缩操作

注意:我们在写html时,可以将公共的部分抽取到common.html文件中,然后在需要用到的地方通过@@include('./common.html')引回来

//html任务
const htmlmin = require('gulp-htmlmin'); //引入插件
const fileinclude = require('gulp-file-include');
gulp.task('htmlmin', done => {
    gulp.src('./src/*.html')
        //抽取公共代码
        .pipe(fileinclude())
        //压缩代码
        .pipe(htmlmin({ collapseWhitespace: true }))
        //输出到目标位置
        .pipe(gulp.dest('dist'));
    done();
});

运行:npm install gulp-htmlminnpm install gulp-file-includegulp htmlmin
结果:在目标位置生成了一个压缩的代码文件(已经把公共部分合并了)

b. css任务:less代码转换+css代码压缩
//css任务 less语法转换 css代码压缩
const less = require('gulp-less'); //引入
const csso = require('gulp-csso');
gulp.task('cssmin', done => {
    //选择css目录下的所有less和css文件
    gulp.src(['./src/css/*.less', './src/css/*.css'])
        //less转换为css
        .pipe(less())
        //css代码压缩
        .pipe(csso())
        //将处理的结果输出
        .pipe(gulp.dest('dist/css'))
    done();
})

运行:npm install gulp-lessnpm install gulp-cssogulp cssmin
结果:在目标位置生成压缩的css文件,less代码也相应被转化

c. js任务:es6转换成es5+js代码压缩
//js任务 es6转换 代码压缩
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
gulp.task('jsmin', done => {
    gulp.src('./src/js/*.js')
        //es6转换成es5
        .pipe(babel({
            // 判断当前代码的运行环境,将代码转换为当前环境所支持的代码
            presets: ['@babel/env']
        }))
        // js代码压缩
        .pipe(uglify())
        .pipe(gulp.dest('dist/js'));
    done();
})

运行:npm install gulp-babel @babel/core @babel/preset-envnpm install gulp-uglifygulp-jsmin
结果:es6语法都被转成es5,并且的带压缩的js文件

d. 复制剩余文件夹
//复制文件夹
gulp.task('copy', done => {
    gulp.src('./src/images/*')
        .pipe(gulp.dest('dist/images'));
    gulp.src('./src/upload/*')
        .pipe(gulp.dest('dist/upload'));
    done();
})

运行:gulp copy

e. 总的构建
//构建任务
// gulp.task('default', ['htmlmin', 'cssmin', 'jsmin', 'copy']); //报错 要放到gulp.series()里
gulp.task('default', gulp.series(['htmlmin', 'cssmin', 'jsmin', 'copy']));

运行:gulp default / gulp 能够依次执行列出的的任务

五、Node.js中模块的加载机制

在这里插入图片描述
在这里插入图片描述

六、package.json文件

在这里插入图片描述
package.json可以解决上述两个问题。

1. 方便第三方模块的下载

在根目录下,使用npm init -y来生成package.json文件,-y表示直接使用默认值
当我们下载了一些第三方模块时,package.json文件都有记录

package.json

{
  "name": "description", 
  "version": "1.0.0",
  "description": "",
  "main": "index.js", //项目的主入口文件
  "scripts": { //命令的别名
  	//我们可以使用npm run test 来简化命令
    "test": "echo \"Error: no test specified\" && exit 1" 
  },
  "keywords": [], //描述当前项目的关键字
  "author": "",
  "license": "ISC", //项目遵循的协议  ISC开放源代码协议
  "dependencies": { //依赖的第三方模块 项目依赖 
    "formidable": "^1.2.2", //通过npm install formidable 下载时会添加进来
    "mime": "^2.5.2"
  },
  "devDependencies": { //开发依赖
    "gulp": "^4.0.2" //通过npm install gulp --save-dev 下载时会添加进来
  }
}

项目依赖与开发依赖
项目依赖是运行项目必须的,开发依赖只是在开发阶段的辅助工具,不是必须的
在这里插入图片描述
在这里插入图片描述
当别人拿到只有package.json 没有node_modules 文件夹的时候,可以在命令行输入
1.npm install :下载所有的依赖,包括项目依赖和开发依赖,用于开发环境中
2.npm install --production:只下载项目依赖,用于生产环境(线上/服务器运营环境)

2. 解决模块与模块之间依赖的问题

在这里插入图片描述

七、请求响应原理及http协议

1. 创建web服务器

app.js:

//创建网站服务器模块
const http = require('http');
//app对象:网站服务器对象
const app = http.createServer();
//当客户端有请求的时候 req请求对象 res结果对象
app.on('request', (req, res) => {
    res.end('<h2>hello vivian</h2>');
});
//监听端口
app.listen(3000);
console.log('网站服务器启动成功');

运行,启动成功
在这里插入图片描述
访问:在浏览器地址栏输入:http://localhost:3000/

2. http协议

http:超文本传输协议,规定了如何从网站服务器传输超文本到本地浏览器,两者请求与应答的标准。
报文:请求和响应过程中携带的数据块

获取请求方式req.method

    //获取请求方式 req.method
    if (req.method == 'POST') {
        res.end('post');
    } else if (req.method == 'GET') {
        res.end('get');
    }

当直接在浏览器输入localhost:3000时,是get请求
在这里插入图片描述
当往服务器提交表单时,是post请求

    <form action="http://localhost:3000" method="post">
        <input type="submit">
    </form>

点击提交按钮后显示
在这里插入图片描述

获取请求地址req.url

    if (req.url == '/index' || req.url == '/') {
        res.end('welcome to homepage');
    } else {
        res.end('not found');
    }

在这里插入图片描述

获取请求头部信息req.header

可以通过req.headers[‘accept’]获取具体信息。

设置响应状态码和返回内容类型

    //设置响应的状态码
    res.writeHead(200, {
        //纯文本,不能解析html
        //'content-type': 'text/plain',
        //可以解析html
        //'content-type': 'text/html',
        //中文不会乱码
        'content-type': 'text/html;charset=utf8'
    });

get请求参数

浏览器中输入:
http://localhost:3000/index?name=vivian&age=21
服务器接收解析参数:
const url = require('url'); 引入url模块
url.parse(req.url, true)

    //解析url true表示查询参数query解析成对象形式
    //console.log(url.parse(req.url, true));
    let { query, pathname } = url.parse(req.url, true);
    console.log(query);
    console.log(pathname);
    //路径判断(路由)
    if (pathname == '/index' || pathname == '/') {
        res.end('<h2>welcome 到 homepage</h2>');
    } else {
        res.end('not found');
    }

post请求参数

表单输入:

    <form action="http://localhost:3000" method="post">
        <input type="text" name="username" id="">
        <input type="password" name="password" id="">
        <input type="submit">
    </form>

服务器接收处理:
const querystring = require('querystring'); 引入querystring内置模块

app.on('request', (req, res) => {
    let postParams = '';
    //当请求参数传递时发出data事件
    req.on('data', params => {
        postParams += params;
    });
    //当参数传递完成时发出end事件
    req.on('end', () => {
        console.log(querystring.parse(postParams));
    });
    res.end('ok');
});

路由

就是请求什么响应什么,例如请求首页就响应首页,这个过程就是路由,需要一系列的判断代码

const http = require('http');
const url = require('url');
const app = http.createServer();
app.on('request', (req, res) => {
    //获取请求方式
    const method = req.method.toLowerCase();
    //获取请求地址
    const pathname = url.parse(req.url, true).pathname;

    res.writeHead(200, {
        'content-type': 'text/html;charset=utf8'
    });

    if (method == 'get') {
        if (pathname == '/' || pathname == '/index') {
            res.end('欢迎来到首页');
        } else if (pathname == '/list') {
            res.end('欢迎来到列表页');
        } else {
            res.end('您访问的页面不存在');
        }
    } else if (method == 'post') {

    }
});
app.listen(3000);
console.log('服务器启动成功');

静态资源

不需要处理可以直接返回的资源,如css、js、image文件

const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const mime = require('mime');

const app = http.createServer();
app.on('request', (req, res) => {

    //获取用户的请求路径
    let pathname = url.parse(req.url).pathname;
    pathname = pathname == '/' ? '/index.html' : pathname;
    //将用户的请求路径转换为实际服务器硬盘路径
    let realPath = path.join(__dirname, 'public' + pathname);

    //获取路径对应资源的类型
    let type = mime.getType(realPath)
    //读取文件
    fs.readFile(realPath, (error, result) => {
        //如果文件读取失败
        if (error != null) {
            res.writeHead(404, {
                'content-type': 'text/html;charset=utf8'
            });
            res.end('文件读取失败');
            return;
        }
        //指定返回资源的类型
        res.writeHead(200, {
            'content-type': type
        })
        res.end(result);
    })
});
app.listen(3000);
console.log('服务器启动完成');

动态资源

相同的请求地址可以请求不同的响应资源

八、Node.js异步编程

1. 同步API

  • 只有当前API执行完成之后,才能继续执行下一个API
  • 可以从返回值中得到结果

2. 异步API

  • 当前API的执行不会阻塞后续代码的执行,执行的顺序看事件循环过程
  • 通过回调函数获得结果

3. 回调地狱

需求:依次读取1,2,3三个文件

const fs = require('fs');
fs.readFile('./1.txt', 'utf8', (err, result1) => {
    console.log(result1);
    fs.readFile('./2.txt', 'utf8', (err, result2) => {
        console.log(result2);
        fs.readFile('./3.txt', 'utf8', (err, result3) => {
            console.log(result3);
        })
    })
});

4. promise

解决回调地狱问题

const fs = require('fs');
function p1() {
    return new Promise(resolve => {
        fs.readFile('./1.txt', 'utf8', (err, result) => {
            resolve(result);
        })
    })
};
function p2() {
    return new Promise(resolve => {
        fs.readFile('./2.txt', 'utf8', (err, result) => {
            resolve(result);
        })
    })
};
function p3() {
    return new Promise(resolve => {
        fs.readFile('./3.txt', 'utf8', (err, result) => {
            resolve(result);
        })
    })
};

p1().then((r1) => {
    console.log(r1);
    return p2();
}).then((r2) => {
    console.log(r2);
    return p3();
}).then((r3) => {
    console.log(r3);
})

5. 异步函数

异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了。
const fn = async () => {};
async function fn() {};

  • 异步函数的默认返回值是promise对象,使用return返回promise对象,相当于resolve方法
  • 使用throw抛出错误
  • await promise 可以暂停异步函数的执行,等待promise对象返回结果后再向下执行
  • 可以调用then、catch获取结果
const fs = require('fs');
async function p1() {
    fs.readFile('./1.txt', 'utf8', (err, result) => {
        console.log(result);
    })
}
async function p2() {
    fs.readFile('./2.txt', 'utf8', (err, result) => {
        console.log(result);
    })
}
async function p3() {
    fs.readFile('./3.txt', 'utf8', (err, result) => {
        console.log(result);
    })
}
async function run() {
    await p1();
    await p2();
    await p3();
}
run();
const fs = require('fs');
//promisify方法中,传入一个异步函数,返回一个promise对象
const promisify = require('util').promisify;
const readFile = promisify(fs.readFile);

async function run() {
    let r1 = await readFile('./1.txt', 'utf8');
    let r2 = await readFile('./2.txt', 'utf8');
    let r3 = await readFile('./3.txt', 'utf8');
    console.log(r1, r2, r3);
}
run();

九、node.js 全局对象global

在浏览器中全局对象是window,在node中全局对象是global
global有以下方法,其中global可以省略
console.log()
setTimeout()
clearTimeout()
setInterval()
clearInterval()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值