Node.js

Node.js

服务端开发要做的事情:实现网站的业务逻辑,数据的增删改查。

Node是一个基于Chrome V8引擎的JS代码运行环境。

Node.js组成:ECMAScript和Node模块Api.

Node全局对象global.

Node中全局对象有以下方法,可以在任何地方使用,global可以省略。

console.log()  在控制台中输出

setTimeout()  设置超时定时器

clearTimeout()  清除超时定时器

setInterval()  设置间歇定时器

clearInterval()  清除间歇定时器

Node.js规定一个js文件就是一个模块,模块内部定义的变量,和函数默认情况下在外部无法得到。

模块内部可以使用exports对象进行成员导出,使用require方法导入其他模块。

模块成员导出

//a.js

let version = 1.0;

const sayHi = name => `您好,${name}`;

exports.version = version;

exports.sayHi = sayHi;

模块成员导入

//b.js

let a = require('./b.js');

console.log(a.version);

console.log(a.sayHi('黑马讲师');

导入模块时后缀可以省略。

模块成员导出的另一种方式

module.exports.version=version;

module.sayHi=sayHi;

exports 是 module.exports的别名(地址引用关系),导出对象最终以module.exports为准。

系统模块

1.文件模块-读取文件、写入文件、创建文件夹

系统模块fs文件操作

const fs =require('fs');

读取文件内容

fs.reaFile('文件路径/文件名称',['文件编码'],callback);

写入文件

fs.writeFile('文件路径/文件名称','数据',callback);

const content = `<h3>正在使用fs.writeFile写入文件内容</h3>';

fs.writeFile('../index.html',content,err => {

  if (err != null) {

      console.log(err);

      return;

  }

  console.log('文件写入成功');

});

2.系统模块path 路径操作

为什么要进行路径操作-

不同操作系统的路径分隔符不统一

/public/upload/avatar

Window上是\  /

Linux上是/

路径拼接语法

path.join('路径','路径',...)

导入path模块

const path = require('path');

路径拼接

let finialPath = path.join('itcast','a','b','c.css');

输出结果itcast/a/b/c.css

console.log(finialPath);

相对路径vs绝对路径

大多数情况下使用绝对路径,因为相对路径有时候相对的是命令行工具的当前工作目录,在读取文件或者设置文件路径时都会选择绝对路径,使用_dirname获取当前文件所在的绝对路径。

第三方模块

获取第三方模块

npm: node的第三方模块管理工具

下载:npm install 模块名

卸载:npm uninstall package 模块名称

全局安装与本地安装

    命令行工具:全局安装

    库文件:本地安装

第三方模块nodemon 是一个命令行工具,用以辅助项目开发,自动刷新。

使用步骤:使用npm install nodemon -g 下载它

在命令行工具中用nodemon命令替代node命令执行文件。

第三方模块nrm:npm下载地址切换工具

npm默认的下载地址在国外,国内下载速度慢

使用步骤:

使用npm install nrm -g下载它

查询可用的下载地址列表 nrm ls

切换npm下载地址nrm use 下载地址名称

第三方模块Gulp

基于node平台开发的前端构建工具,将机械操作编写成任务,想要执行机械化操作时执行一个命令行命令任务就能自动执行了,用机械代替手工,提高开发效率。

Gulp能做什么:

项目上线,HTML,css,js文件压缩合并,语法转换(es6,less...),公共文件抽离,修改文件浏览器自动刷新。

Gulp使用:

使用npm install gulp下载gulp库文件,

在项目根目录下建立gulpfile.js文件,

重构项目的文件夹结构src目录放置源代码文件dist目录放置构建后文件,

在gulpfile.js文件中编写任务,

在命令行工具中执行gulp任务。

Gulp提供的方法:

gulp.src()  获取任务要处理的文件

gulp.dest()  输出文件

gulp.task()  建立gulp任务

gulp.watch()  监控文件的变化

const gulp = require('gulp');

//使用gulp.task()方法建立任务

gulp.task('first', () => {

//获取要处理的文件

  gulp.src('./src/css/base.css');

  //将处理后的文件输出到dist目录

.pipe(gulp.dest(./dist/css));

});

Gulp插件

gulp-htmlmin:html文件压缩

gulp-csso :压缩css

gulp-babel :js语法转换

gulp-less:less语法转换

gulp-uglify : 压缩混淆js

gulp-file-include : 公共文件包含

browsersync浏览器实时同步

package.json文件

node_modules 文件夹的问题-记录模块依赖关系。

package.json文件的作用-项目描述文件,记录当前项目信息,

使用npm init -y命令生成。

项目依赖-dependencies字段

开发依赖-devDependencies

package-lock.json文件的作用

锁定包的版本,确保再次下载时不会因为版本不同而产生问题。

模块查找规则-当模块拥有路径但没有后缀时

require('./find.js');

require('./find');

require方法根据模块路径查找模块,如果是完整路径,直接引入模块。

如果模块后缀省略先找同名JS文件再找同名JS文件夹。

如果找到了同名文件夹,找到文件夹中的index.js。

如果文件夹中没有index.js,就会去当前文件夹中的package.json文件中查找main选项中的入口文件。

如果找指定的入口文件不存在或者没有指定入口文件就会报错,模块没有被找到。

require('find');

Node.js会假设它是系统模块。

Node.js会去node_modules文件夹中。

首先看是否有该名字的JS文件。

再看是否有该名字的文件夹。

如果是文件夹看里面是否有index.js。

如果没有index.js查看该文件夹中的package.json中的main选项确定模块入口文件。

否则找不到报错。

【请求相应原理及HTTP协议】

1.服务器端基础概念

网站的组成-客户端和服务器端。

Node网站服务器

Ip地址

域名-网址

端口-计算机与外界通讯交流的出口,用来区分服务器电脑中提供的不同的服务。

URL-统一资源定位符,组成

  传输协议://服务器ip或域名:端口/资源所在的位置标识

http://www.itcast.cn/news/20181018/09152238514.html

http超文本传输协议,提供了一中的发布和接受html页面方法。

本机域名localhost

本机ip: 127.0.0.1

2.创建web服务器

//引用系统模块

const http = require('http');

//创建web服务器

const app = http.createServer();

//当客户端发送请求的时候

app.on('request', (req,res) => {

    //响应

    red.end('<h1>hi,user</h>');

});

//监听3000端口

app.listen(3000);

console.log('服务器已启动,监听3000端口,请访问localhost:3000');

3.HTTP协议

http协议概念:

超文本传输协议,规定了如何从网站服务器传输超文本到本地浏览器,它基于客户端服务器框架工作,是客户端和服务器端请求和应答的标准。

报文:在http请求和响应的过程中传递的数据块就叫报文,包括要传送的数据和一些附加信息,并且要遵守规定好的格式。

请求报文

请求方式:GET  请求数据  POST  发送数据

请求地址:

app.on('request',(req,res) => {

    req.headers  //获取请求报文

    req.url        //获取请求地址

    req.method  //获取请求方法

});

响应报文

Http状态码

200请求成功

404请求的资源没有被找到

500服务器端错误

400客户端请求有语法错误

内容类型

text/html

text/css

application/javascript

image/jpeg

application/json

app.on('request', (req,res) =>{

    //设置响应报文

    red.writeHead(200, {

          'Contwnt-Type': 'text/html;charset=utf8'

    });

});

请求参数

GET请求参数

参数放置在浏览器地址栏中,例如http://localhost:3000/?name=li&age=18

参数获取需要借助系统模块url,  url模块用来处理url地址。

const http = require('http');

//导入url系统模块,用于处理url地址

const url = require('url');

const app = http.createServer();

app.on('request', (req,res) => {

    //将url路径的各个部分解析出来并返回对象

    //true 代表将参数解析为对象格式

    let {query} = url.parse(req.url,true);

    console.log(query);

});

app.listen(3000);

POST请求参数

参数被被放置在请求体中进行传输

获取POST参数需要使用data事件和end事件

使用querystring系统模块将参数转换为对象格式

const http = require('http');

//导入url系统模块,用于处理url地址

const url = require('url');

const app = http.createServer();

app.on('request', (req,res) => {

    //将url路径的各个部分解析出来并返回对象

    //true 代表将参数解析为对象格式

    let {query} = url.parse(req.url,true);

    console.log(query);

});

//导入系统模块querystring用于将HTTP参数转换为对象格式

const querystring = require('querystring');

app.on('request', (req,res) => {

    let postData = '';

    //监听参数传输事件

    req.on('data',(chunk) => postData += chunk;);

  //监听参数传输完毕事件

  req.on('end', () => {

      console.log(querystring.parse(postData);

  });

});

路由

http://localhost:3000/index

http://localhost:3000/login

路由是指客户端请求地址与服务器端程序代码的对应关系,简单来说,就是请求什么响应什么。

GET/index    -路由-    响应首页

GET/list        -路由-    响应列表页

GET/login    -路由-    登录逻辑处理

//当客户端发来请求的时候

app.on('request',(req,res) => {

    //获取客户端的请求路径

    let {pathname} =url.parse(req.url);

    if(pathname == '/' || pathname == '/index') {

        res.end('欢迎来到首页');

    } else if ( pathname == '/list') {

        res.end('欢迎来到列表页');

    } else {

        red.end('抱歉,您访问的页面出游了');

    }

});

静态资源

服务端不需要处理,可以直接响应给客户端的资源就是静态资源,例如CSS,JavaScript,image文件。

http://www.itcast.cn/image/logo.png

动态资源

相同的请求地址不同的响应资源,这种资源就是动态资源。

http://www.itcast.cn/article?id=1

http://www.itcast.cn/article?id=2

客户端请求途径

GET方式

浏览器地址栏

link标签的href属性

script标签的src属性

img标签的src属性

Form表单提交

POST方式

Form表单提交

Node.js异步编程

同步API,异步API

//拼接路径

const public = path.join(__dirname,'public');

//请求地址解析

const urlObj = url.parse(req.url);

//读取文件

fs.readFile('./demo.txt','utf8', (err,result) => {

    console.log(result);

});

同步api:只有当前api执行完成后,才能继续执行下一个api

console.log('before');

console.log('after');

异步api:当前api执行不会阻塞后续代码的执行。

console.log('before');

setTimeout (

    () => { console.log('last');

},2000);

console.log('after');

同步api和异步api的区别(获取返回值)

同步api可以从返回值中拿到api执行的结果,但是异步api是不可以的。

//同步

function sum (n1,n2) {

    return n1+ n2;

}

const result = sum(10,20);

//异步

function getMsg () {

    setTimeout(function ()

        return { msg : 'Hello node.js'}

    },2000);

}

const msg = getMsg();

回调函数

自己定义函数让别人调用

//getData函数定义

function getData (callback) {}

//getData函数调用

getData( () => {});

使用回调函数获取异步API执行结果

function getMsg (callback) {

      setTimeout(function () {

          callback ( {msg : 'Hello node.js'})

      },2000);

}

getMsg ( function (msg) {

      console.log(msg);

});

同步Api,异步Api的区别(代码执行顺序)

同步api从上到下依次执行,前面代码会阻塞后面代码的执行。

for(var i=0; i<100000; i++) {

      console.log(i);

}

console.log('for循环后面的代码');

异步Api不会等待api执行完成后再向下执行代码。

代码执行顺序分析

Node.js中的异步Api

fs.readFile('./demo.txt', (err,result) => {});

ver server = http.createServer ();

server.on('request', (req,res) => {});

如果异步Api后面代码的执行结果,但实际上后续代码在执行的时候异步Api还没有返回结果,这个问题要怎么解决?

fs.readFile('./demo.txt', (err,result) => {});

console.log('文件读取结果');

Promise

出现的目的是解决Node.js异步编程中回调地狱的问题。

let promise = new Promise (resolve, reject) => {

    setTimeout ( ()=> {

      if (true) {

        resolve({name : '张三'})

      } else {

        reject('失败了')

      }

    },2000);

});

promise.then(result => console.log(result);

          .catch(err => console.log(error);

异步函数

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

const fn = async () => {};

async function fn () {}

async 关键字

普通函数定义前加async关键字,普通函数变成异步函数。

异步函数默认返回promise 对象。

在异步函数内部使用return 关键字进行结果返回,结果会包裹在promise对象中,return 关键字代替了resolve 方法。

在异步函数内部使用throw关键字抛出程序异常。

调用异步函数再链式调用then方法获取异步函数执行结果。

调用异步函数再链式调用catch方法获取异步函数执行的错误信息。

await关键字只能出现在异步函数中。

await promise await 后面只能写promise 对象,写其他类型的api是不可以的。

await关键字可是暂停异步函数向下执行,直到promise返回结果。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335