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);
}
})
});

  

 


posted @ 2019-11-10 22:25  skyflask  阅读(542)  评论(0编辑  收藏  举报