Nodejs入门
一、nodejs简介
nodejs的由来、解决的问题。
nodejs是一个服务端工具,使用js语言,集成了自身的很多模块。
nodejs特点:单线程、非阻塞IO、事件驱动。
多线程在处理高并发的时候,需要的资源也会随着请求数增加而增加,
在大多数场景下,我们的并发并不是很高,尤其是中小型站点,资源要求很低,响应速度还很快。
nodejs让不适应于大型站点,毕竟大型站点是少数。
为了处理请求更快,nodejs采用了非阻塞IO(异步IO),有了异步IO还是不能很好的完成单线程请求,
我们还要有一个事件驱动机制,把回调结果及时传给之前的请求。
二、nodejs中的模块
1、模块A暴露,模块B引用
模块A要被其他模块引用,必须先暴露对应的内容,可以是变量,也可以是函数、类等。
一个模块的本质是一个函数,所以模块B引用模块A的时候,需要先导入。(函数有自己的命名空间,是私有属性和方法)
2、查看模块是函数的方法:
console.log(arguments.callee + '');
可以得知实际的函数是:
function (exports, require, module, __filename, __dirname) {
console.log(arguments.callee + '');
}
3、模块中的所有代码都是函数体,并且在函数执行的同时传递进了5个实参
exports:该对象用来将函数内部的局部变量或局部函数暴露到外部
require:用来引入外部的模块
module:代表的是当前模块本身, exports就是module的属性; 我们既可以使用 exports 导出,也可以使用module.exports导出
__filename:当前模块的完整路径
__dirname:当前模块所在文件夹的完整路径
4、模块暴露的两种方法
exports和module.exports
(function(exports,require,module,__filename,__dirname){
exports = module.exports={};
......
return module.exports;
})
5个参数里面的module表示当前模块本身,exports是暴露模块的属性。
二者的不同之处:
============================
let site = '撩课学院';
let func = ()=>{
console.log(site);
};
let obj = {
name: '张三'
};
exports.site = site;
exports.func = func;
exports.obj = obj;
module.exports.site = site;
module.exports.func = func;
module.exports.obj = obj;
//当二者通过属性(值类型,类似python中的不可变元素)进行对外暴露时,二者的引用地址是一样的
//但是,当二者通过对象进行对外暴露时,相当于二者的引用地址已经改变了。
//所以,通过exports方式到时候,在其他模块导入当前模块时,内容为空对象{},而module.exports为真正的对象。
exports和module.exports的区别:
exports只能使用 . 语法来对外暴露变量;
module.exports即可以使用.语法,也可以赋值给一个对象来暴露
exports指向的对象是module.exports的指针。
/*
module.exports = {
site,
func,
obj
};
这里会输出
{ site: '撩课学院', func: [Function: func], obj: { name: '张三' } }
*/
/*exports = {
site,
func,
obj
};
这里会输出
{}
*/
==============================================
三、模块类型
内建模块:由C++编写的,无需require,类似python中的abs、sum
文件模块:自己写的模块
核心模块:由node引擎提供的模块
原生模块:fs/http/path等,需要require
第三方模块:npm install的,别人写好的模块。类似python中通过pip安装的模块。
注意:内建模块和原生模块的区别是需要require,类似python中的 abs模块和os模块的区别。abs模块无需import,而os模块需要import后才能使用。
node是一个工具,它本身并不是一门语言,而是需要通过js来实现,而JavaScript中只保留了ECMAScrip,没有Dom和Bom。
取而代之的是一堆的模块。
四、npm(node package manager)
node里面的包管理,通过npm init初始化生成包信息,package.json文件会有包管理信息,包括包名、版本信息。其他人可以根据package.json直接执行npm install就可以安装依赖,把环境跑起来。
五、模块学习
fs模块
stream模块
pipe管道
http模块
六、简易web服务器
1、简易web服务器搭建
const http = require('http');
const server = http.createServer((req,res)=>{
//各种中间介处理
}).listen(3000,'127.0.0.1',()=>{
console.log('server is running');
});
2、url解析方法
//老的方式,url.parse
const url = require('url');
const myURL = url.parse('http://www.baidu.com:9999/p/a/t/h?name=xuequn&age=22');
console.log(myURL);
//新的方式,通过URL实例化一个对象
const myURL = new URL('http://www.baidu.com:9999/p/a/t/h?name=xuequn&age=22');
console.log(myURL);
3、http日志记录和response头设置
//通过写流直接wirte内容
let out = fs.createWriteStream(path.join(__dirname,'requrest.log'));
out.write('01method:'+req.method+'\n');
//response头设置
const http = require('http');
http.createServer((req, res)=>{
console.log(res.headersSent ? '响应头已经发送' : '响应头未发送');
// 设置隐式响应头
res.setHeader('Content-Type', 'text/html;charset=utf-8');
res.writeHead(200, 'ok');
res.write('<h1>Hello, World!</h1>');
// 本次响应结束
res.end('<h1>你好,世界!</h1>');
console.log(res.headersSent ? '响应头已经发送' : '响应头未发送');
}).listen(3000, '127.0.0.1', ()=>{
console.log('服务器已经启动~')
});
4、http处理post数据
const http = require('http');
const queryString = require('querystring');
const util = require('util');
let server = http.createServer((req,res)=>{
let postData='';
// post请求, 得做事件监听
req.on('data', (data)=>{
postData+=data;
});
// 监听数据接收完毕
req.on('end', ()=>{
//解析post数据
postData = queryString.parse(postData);
console.log(postData.user);
console.log(postData.pwd);
res.end('数据接收成功!');
});
}).listen(3000, '127.0.0.1');
5、web服务器多页面处理
原理:通过文件名和路由对比,读取文件,然后设置headers后,res.end返回数据到前端。
6、web服务器多页面处理改进版本
5中每次通过文件名和路由对比的方式对于页面比较多的情况,十分不友好。
改进方法:通过判断前端请求的路由,读取出文件,然后根据文件的后缀进行headers设置后,然后返回给前端。
七、express入门
1、express入门
express的核心:路由、视图、中间介。
中间介通过next参数以及next()调用进行中间介的流动。
视图用于实现业务逻辑的部分。
路由是不同url对应不同的业务逻辑功能和页面反馈。
典型的架构模式:MVC
2、Express 应用程序生成器
通过应用生成器工具 express-generator
可以快速创建一个应用的骨架。
express-generator
包含了 express
命令行工具。通过如下命令即可安装:
npm install express-generator -g
-h
参数可以列出所有可用的命令行参数:
$ express -h Usage: express [options] [dir] Options: -h, --help 输出使用方法 --version 输出版本号 -e, --ejs 添加对 ejs 模板引擎的支持 --hbs 添加对 handlebars 模板引擎的支持 --pug 添加对 pug 模板引擎的支持 -H, --hogan 添加对 hogan.js 模板引擎的支持 --no-view 创建不带视图引擎的项目 -v, --view <engine> 添加对视图引擎(view) <engine> 的支持 (ejs|hbs|hjs|jade|pug|twig|vash) (默认是 jade 模板引擎) -c, --css <engine> 添加样式表引擎 <engine> 的支持 (less|stylus|compass|sass) (默认是普通的 css 文件) --git 添加 .gitignore -f, --force 强制在非空目录下创建
例如,如下命令创建了一个名称为 myapp 的 Express 应用。此应用将在当前目录下的 myapp 目录中创建,并且设置为使用 Pug 模板引擎(view engine):
$ express --view=pug myapp create : myapp create : myapp/package.json create : myapp/app.js create : myapp/public create : myapp/public/javascripts create : myapp/public/images create : myapp/routes create : myapp/routes/index.js create : myapp/routes/users.js create : myapp/public/stylesheets create : myapp/public/stylesheets/style.css create : myapp/views create : myapp/views/index.pug create : myapp/views/layout.pug create : myapp/views/error.pug create : myapp/bin create : myapp/bin/www
然后安装所有依赖包:
$ cd myapp $ npm install
在 MacOS 或 Linux 中,通过如下命令启动此应用
$ DEBUG=myapp:* npm start
在 Windows 中,通过如下命令启动此应用:
> set DEBUG=myapp:* & npm start
然后在浏览器中打开 http://localhost:3000/
网址就可以看到这个应用了。
通过生成器创建的应用一般都有如下目录结构:
. ├── app.js ├── bin │ └── www ├── package.json ├── public │ ├── images │ ├── javascripts │ └── stylesheets │ └── style.css ├── routes │ ├── index.js │ └── users.js └── views ├── error.pug ├── index.pug └── layout.pug 7 directories, 9 files
express脚手架目录结构:
bin:服务器启动文件
public:静态文件
routes:路由文件
views:视图文件
app.js:项目入口文件
八、MongoDB基础和CURD
九、配置babel
目的:转化高阶语法
babel基础配置:
a、新建.babelrc文件
b、配置babel为开发环境
{
"presets": [
"env"
]
}
c、npm install babel-preset-env --save-dev(编译环境准备)
为什么要用--save-dev?生产环境不需要,上线部署:npm install --production
d、npm i babel-register --save-dev(es6转es5的转换工具)
babel-register可以理解成一个小插件,将es6的东西转成es5
e、babel启动环境配置
新建main.js
1)中间过渡
require('babel-register');
require('./app');
2)app.js
// const express = require('express');
import express from 'express'
3)运行
node main.js
f、babel高阶语法转换过程
1)安装
npm install -g babel-cli npm install babel-cli --save-dev
2)转化
babel ./app.js
3)保存转换后的文件到指定目录
babel src -d dist
4) 开发和生产环境分离配置
package.json文件修改:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "node main.js",
"build": "babel src -d dist",
"start": "node dist/app.js"
},
a、开发环境
npm run dev
b、线上环境
npm run build
npm run start
十、项目配置
a、配置静态路径,并抽取到配置文件config.js
import {join} from 'path';
export default {
viewsPath: join(__dirname, '../views'),
publicPath: join(__dirname, '../public'),
}
b、配置公共资源访问路径app.js
app.use(express.static(config.publicPath));
c、配置模板引擎(nunjucks模板引擎能够作用到views文件夹中的模板)app.js
nunjucks.configure(config.viewsPath, {
autoescape: true,
express: app,
noCache: true // 不使用缓存,模板每次都会重新编译
});
d、引入路由
import indexRouter from './../routes/index'
e、挂载路由
app.use(indexRouter);
十一、自动重启更新操作
npm i nodemon -g --save
修改package.json文件中的启动方式:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "nodemon main.js",//开发环境
"build": "babel src -d dist",// 打包
"start": "node dist/app.js" // 启动打包后的文件
},
十二、使用nunjucks模板
模块化思想
和jinjia2类似
基础模板制作:base抽取
十三、nodejs中使用第三方模块
a、安装
npm i jquery --save
b、配置路径
//配置访问外部资源,通过静态static方式访问
app.use('/node_modules', express.static(path.join(__dirname, '/node_modules')));
c、引入
//访问node_modules,其实就是后面的静态static路径
<script src="node_modules/jquery/dist/jquery.js"></script>
十四、文件上传
服务端:
1、原生方式提交:
app.post('/', (req, res, next)=>{ console.log('1111'); let data = ''; req.on('data', (chunk)=>{ data += chunk; }); req.on('end', ()=>{ fs.writeFile(path.join(__dirname, 'data.txt'), data, (err)=>{ if(!err){ res.end('success!'); } }); }); });
2、formdata方式提交:
app.post('/', (req, res, next) => { // 1. 创建实例 let form = new formidable.IncomingForm(); // 2. 指定文件的上传文件夹 form.uploadDir = path.join(__dirname, 'dir'); // 3. 指定文件的后缀 form.keepExtensions = true; // 解析request发送过来的数据 form.parse(req, function(err, fields, files) { if(err){ throw err; } console.log(fields); console.log(files); res.end('success'); }); });
客户端:
1、原生方式
原生方式提交,客户端无须操作。
2、formdata上传
$('#btn_sub').on('click', function () { var $form = $('form'); $.ajax({ url:$form.attr('action'), type:$form.attr('method'), //实例化formdata,会把input里面的键值对解析 data: new FormData($form[0]), // 不要处理转化成一个查询字符串 processData: false, contentType: false, success: function (data) { console.log(data); } }) });