node.js是什么?
-
node.js一个让javascript运行在服务端的开发平台
-
node.js不是一门语言
-
node.js不是库,不是框架
-
node.js是一个JavaScript运行时环境
-
node.js是可以解析和执行js代码,以前只有浏览器可以解析JavaScript
-
也就是说有了node,JavaScript可以完全脱离浏览器运行。
-
构建与chrome的v8引擎上
-
代码只是具有特定格式的字符串
-
引擎可以识别他们,引擎会帮你去解析和执行
-
chrome的v8引擎,是目前公认执行js最快的引擎
-
node的作者把v8引擎提取出来,编译成了JavaScript的运行环境
-
-
浏览器中的JavaScript
-
EcmaScript
-
Bom
-
Dom
-
-
node中的JavaScript
-
只有EcmaScript
-
没有Dom和Bom
-
node这个JavaScript运行时环境为JavaScript提供了一些服务器级别的操作API
-
例如文件读写
-
网络服务的构建
-
网络通讯
-
http服务器等
-
-
-
-
node.js使用机制
-
事件驱动
-
非阻塞io模型,简单来说就是异步操作
-
-
node.js生态系统
-
npm(世界上最大的开源库生态系统)
-
绝大数的JavaScript包都存放在npm上,让开发人员更方便的下载使用
-
node.js能做什么?
- web服务器后台
- 命令行工具(npm,hexo)
- 一些资源
- 《深入淡出Node.js》
- 《node.js权威指南》
node.js学完能学到什么?
- B/S编程模型
- Brower-server
- back-end
- 任何服务端技术这种BS编译模型都是一样的,和语言无关
- 模块化编程
- 通过commin.js导入导出对应模块
- 异步编程
- 回调函数
- promise
- async
- generator
模块系统
-
模块系统
-
在 Node 中没有全局作用域的概念
-
在 Node 中,只能通过 require 方法来加载执行多个 JavaScript 脚本文件
-
require 加载只能是执行其中的代码,文件与文件之间由于是模块作用域,所以不会有污染的问题
-
模块完全是封闭的
-
外部无法访问内部
-
内部也无法访问外部
-
-
模块作用域固然带来了一些好处,可以加载执行多个文件,可以完全避免变量命名冲突污染的问题
-
但是某些情况下,模块与模块是需要进行通信的
-
在每个模块中,都提供了一个对象:exports
-
该对象默认是一个空对象
-
你要做的就是把需要被外部访问使用的成员手动的挂载到exports接口对象中
-
然后谁来require这个模块,谁就可以得到模块内部的exports接口对象
-
还有其它的一些规则,具体后面讲,以及如何在项目中去使用这种编程方式,会通过后面的案例来处理
-
-
核心模块
-
核心模块是由 Node 提供的一个个的具名的模块,它们都有自己特殊的名称标识,例如
-
fs 文件操作模块
-
http 网络服务构建模块
-
os 操作系统信息模块
-
path 路径处理模块
-
。。。。
-
-
所有核心模块在使用的时候都必须手动的先使用require方法来加载,然后才可以使用,例如:
- var fs = require(‘fs’)
-
使用node编写应用程序主要就是在使用- ECMAscript- 核心模块- fs模块- http模块- url模块- 第三方模块- 自定义模块
-
1、什么是模块化
-
文件作用域
-
通讯规则
-
- commonJS模块规范
在node中的JavaScript还有一个跟重要的概念,模块系统
- 模块作用域
- 使用require方法来加载模块
- 使用export 接口对象来导出模块中的成员
- 加载 require
两个作用
- 执行被加载 模块的代码
- 得到被加载模块中的exports导出接口对象
- 导出 export
- node中是模块作用域,默认文件中所有的成员只在当前文件模块有效
- 对希望可以被其他模块访问的成员,我们需要把这些公开的成员挂在到exprots接口对象中就可以了
- 导出多个成员
```js
export.a = 123
export.b = 456
export.c=789
```
- 导出单个成员
```js
module.export = 'hello'
module.export = {
}
```
模块原理 接下来我们介绍一下原理
-
exports 和 module.exports 的区别
-
每个模块中都有一个 module 对象
-
module 对象中有一个 exports 对象
-
我们可以把需要导出的成员都挂载到 module.exports 接口对象中
-
也就是:moudle.exports.xxx = xxx的方式
-
但是每次都moudle.exports.xxx = xxx很麻烦,点儿的太多了
-
所以 Node 为了你方便,同时在每一个模块中都提供了一个成员叫:exports
-
exports === module.exports结果为trues
-
所以对于:moudle.exports.xxx = xxx的方式 完全可以:expots.xxx = xxx
-
当一个模块需要导出单个成员的时候,这个时候必须使用:module.exports = xxx的方式
-
不要使用exports = xxx不管用
-
因为每个模块最终向外return的是module.exports
-
而exports只是module.exports的一个引用
-
所以即便你为exports = xx重新赋值,也不会影响module.exports
-
但是有一种赋值方式比较特殊:exports = module.exports这个用来重新建立引用关系的
这个原理有点像构造函数,node中只有模块作用域.每个模板内部都有一个自己的对象module对象,在module对象中也有一个对象export的一个空对象。
默认在代码的最底层有一句话,return module.exports。而其中还有一局代码是var express = module.export 因此才有了export.a = 123这种导入。其实本质还是对module对象中的export导出。
模块查找机制
require 方法加载规则
-
require 方法加载规则
-
优先从缓存加载
-
核心模块
-
路径形式的模块
-
./xxx
-
…/xxxx
-
/xxxx/ 在这里表示的是磁盘根路径
-
c:/xxx
-
-
-
第三方模块
-
第三方模块的标识就是第三方模块的名称(不可能有第三方模块和核心模块的名字一致)
-
npm
-
开发人员可以把写好的框架、库发布到 npm 上
-
使用者在使用的时候就可以很方便的通过 npm 来下载
-
-
使用方式:var 名字 = require(‘npm install 的那个包名’)
-
node_modules
-
node_modules/express
-
node_modules/express/package.json
-
node_modules/express/package.json main
-
如果 package.json 或者 package.json main 不成立,则查找备选项:index.js
-
如果以上条件都不成立,则继续进入上一级目录中的 node_modules 按照上面的规则继续查找
-
如果直到当前文件模块所属磁盘根目录都找不到,最后报错:can not find module xxx
-
-
package.json 包描述文件
-
就是产品的说明书
-
dependencies属性,用来保存项目的第三方包依赖项信息
-
所以建议每个项目都要有且只有一个 package.json (存放在项目的根目录)
-
我们可以通过npm init [–yes]来生成 package.json 文件
-
同样的,为了保存依赖项信息,我们每次安装第三方包的时候都要加上:–save选项。
-
-
npm 常用命令
-
install
-
uninstall
-
-
Express 基本使用
-
使用 Express 把之前的留言本案例自己动手改造一下
标识符分析
- 路径形式的模块
>/(当前文件模块所属磁盘根路径) ./ ../
- 核心模块
>直接应用,这些核心文件已经被编译到二进制文件中了。
- 第三方模板
不可能有任何一个第三方包与核心模块的名字是一样的
>先找到当前文件中的node_modules,你所引入的包/ 再去找到包中对应的pack.json文件/再去找到里面的main属性/main属性中就记录了当前包的入口模块。
>如果pack.json不存在,并且main对应的路径是有问题的那么,那么pack.json文件在同一目录下的index.js文件
服务器渲染与客户端渲染
-
服务端渲染
-
说白了就是在服务端使用模板引擎
-
模板引擎最早诞生于服务端,后来才发展到了前端
-
-
服务端渲染和客户端渲染的区别
-
客户端渲染不利于 SEO 搜索引擎优化
-
服务端渲染是可以被爬虫抓取到的,客户端异步渲染是很难被爬虫抓取到的
-
所以你会发现真正的网站既不是纯异步也不是纯服务端渲染出来的
-
而是两者结合来做的
-
例如京东的商品列表就采用的是服务端渲染,目的了为了 SEO 搜索引擎优化
-
而它的商品评论列表为了用户体验,而且也不需要 SEO 优化,所以采用是客户端渲染
-
《编写可维护的 JavaScript》
-
最少两次请求,发起 ajax 在客户端使用模板引擎渲染
-
客户端拿到的就是服务端已经渲染好的
-
核心模块
-
官方文档
-
fs模块,http模块,path路径模块,os操作系统模块。。。
fs模块
- 文件读取
- fs.readFile(文件中存储的其实二进制0 1)
var fs = require('fs')
fs.readFile('./data/hello.text';
function(error, data) {
if(!error){
var a = data.toString()
console.log(a)
}else{
console.log('读取文件失败')
}
})
这里他呗默认转为了16进制,外面可以通过tostring方法转化成我们能认识的字符
- 写文件
- fs.writeFile
var fs = require('fs');
fs.writeFile('./data/holleword.text',"家好 我是holleword",function(error){
console.log(error)
//没错error = null
})
http模块
node可以非常轻松的构建一个web服务器,在node中提供一个核心模块:http
- 1、加载http核心模块
var http = require('http')
- 2、使用http.createServer()方法创建一个web服务器,返回一个Server实例
var server = http.createServer()
-
3、服务器作用
1、对数据提供服务
2、发送请求
3、接受数据
4、处理请求
5、响应请求
- 配置头部信息
res.setHeader('content-type' , 'text/plain'; charset=utf-8)
文件类型(content-type)
-
非文字类型的都要把charset=utf-8去掉
-
text/plain 普通文本
-
text/html 就是html格式文本工具除了配置请求头中的content-type还可以在html页面的meta标签中声明他
文本编码格式
- 在服务器默认发送的数据,默认都是utf8编码的内容 - 但是浏览器不知道你是什么类型的编码,你也没有告诉浏览器你发送的数据是什么编码 - 那么浏览器在不知道内容编码的情况下,默认按照当前操作系统的默认编码去解析 - 中文操作系统的默认编码格式是 gdk
-
监听request请求,当有客户端发送请求会自动执行request请求事件
-
服务端重定向
-
以3开头的状态码都是用于重定向的。
-
首先设置状态码
res.statusCode = 302
301 永久重定向 浏览器会记住302 零时重定向 浏览器记不住
- 配置重定向地址
res.setHeader('Location','/')
-
var http = require('http')
var server = http.createServer()
server.on('request',function(req,res) {
console.log('收到客户端请求')
console.log('请求地址是'+req.url)
//req.url获取获取请求的url信息
//res中有wrte方法,write可以多次使用但是最后必须使用end结束,如果不接受那么程序会继续等待
res.write('holle')
res.write('word')
res.end()
})
//第二种写法
var http = require('http')
http.createServer(function(req,res){
})
- 4、绑定端口号,启动服务器
server.listen(3000)
- 5、配置路由响应
var http = require('http')
var server = http.createServer()
server.on('request',function(req,res) {
})
path模块
用来帮你辅助操作路径的
dirname 和filename
-
动态的获取当前文件或者文件所处目录的绝对路径
-
用来解决文件操作路劲的相对路径问题
-
因为在文件操作中,相对路径相对于执行node命令所处的目录
-
所以为了尽量避免这个问题,都建议文件操作的相对路劲都转为:动态的绝对路径
-
方式:path.join(__dirname, ‘文件名’)
//获取给定路径的文件名
path.basename('路径') //获取文件明年
path.basename('c/a/index.js') //index.js
//获取给定路径的文件名
path.dirname('路径')
//获取文件扩展名
path.extname('')
//判断是否为绝对路径
path.isAbsolyte(path)
//获取分析路径中所有信息
path.parse('')
//路径拼接
path.join('','')
node中的其他成员
每个模块中,除了require、exports等模块,还有两个特殊成员。
- dirname 可以获取当前文件模块所属目录的绝对路径 (动态的获取)`filename 可以获取当前文件的绝对路径 (动态的获取)
在文件操作中,使用相对路径是不可靠的,因为node中文件操作的路径被设计为相对于执行node命令所处的路径(不是bug,人家这样设计是有使用场景的)为了解决相对路径不可靠的问题,我们把可以使用dirname/filename来动态获取不同计算机不同存储位置的路径。在路径拼接过程中,为了避免手动修改路径出错,所以推荐多使用path.join()来辅助拼接,在以后的操作中尽可能的把绝对路径转化为相对路径。
app.use('/public/',express.static(path.join(__dirname,'./public')))
app.use('/node_modules',express.static(path.join(__dirname,'./node_modules')))
node多文件执行
-
node中没有全局作用域,只有模块作用域。也就是说不同文件中的内容在同一页面执行引入的时候不会相互影响。外部取不到内部的数据,内部也取不到外部的数据,但是可以执行代码。
-
那么如何让node中的模块之间通讯呢?
- export导出模块常规导出的是express这个对象,需要通过打点或者解构来获取和调用里面的多内容
export abc
-
require的作用
-
1、加载并执行文件模块中的代码
-
2、拿到被加载文件模块导出的接口对象
-
-
ip地址和端口号
-
每一个ip指向了一台服务器(定位计算机)
-
服务器中的每一个物联网通讯的应用程序都对应了一个端口号(端口号定位具体应用程序)
-
端口号范围 0 - 65535之间
-
模板引擎
art-template 模板引擎(include、block、extend)
-
include
-
extend
-
block
模板引擎起源于服务器,最后发展到了前端
- art-template(js)
node中静态资源处理方法
node中为了方便静态资源管理放在public文件中
var http = require("http");
var url = require("url");
var fs = require("fs");
http.createServer(function(req,res){
//得到用户的路径
//
var pathname = url.parse(req.url).pathname;
//真的读取这个文件
fs.readFile("./static/" + pathname,function(err,data){
if(err){
//如果此文件不存在,就应该用404返回
fs.readFile("./static/404.html",function(err,data){
res.writeHead(404,{"Content-type":"text/html;charset=UTF8"});
res.end(data);
});
return;
};
res.end(data);
});
}).listen(3000,"127.0.0.1");
实现Apache
推荐JavaScript的编写规范的书
编写可维护的javascript
服务器渲染
也就是说在服务器使用模板引擎
- 客户端渲染html 仅仅作为静态文件,客户端端在请求时,服务端不做任何处理,直接以原文件的形式返回给客户端客户端,然后根据 html 上的 JavaScript,生成 DOM 插入 html。
- 服务端渲染服务端在返回 html 之前,在特定的区域,符号里用数据填充,再给客户端,客户端只负责解析 HTML 。(也就是通过模板引擎把数据在服务端的时候就渲染好,收到请求之间发送页面)
- 客户端渲染与服务器渲染的区别
- 客户端渲染不利于seo搜索引擎优化,也就是说客户端渲染的数据爬虫爬不到
- 服务器渲染是可以被爬虫爬取到的,客户端的异步渲染是很难被爬虫爬取到的。
- 所以一个网站,是服务器与客户端结合渲染来做的
npm
package.json包说明书,描述你的项目使用了哪些npm包
--save 会把你安装的包放在package.json中。
同时package.json可以通过npm init初始化出来
而如果没有node——module有package.json使用npm install 会更具package.json中的依赖还原你的node_module
npm 是一个网站
npm 是一个命令行工具
npm install (i)
npm install 包名 --save(S)
npm uninstall 包名
npm help 查看使用帮助
npm被墙问题
npm是国外网站一般使用cnpm
npm install --global cnpm
如果不想通过npm安装cnpm也可以
npm install 包 --registry=https://registry.npm.taobao.org
这样会比较麻烦每次安装都需要写后缀
推荐这样
npm config set registry https://registry.npm.taobao.org
package.json/package-lock.json
- package-lock.json中存储的你项目中node_module所有的依赖信息,当你的node_module从新安装依赖的时候会比没有安装之前的速度更快。
- 从文件来看,有一个lock 这个锁是用来锁定版本的,如果你下载的下面时1.1版本的,如果没有lock那么你npm i的时候就会默认给你安装最新的版本
JavaScript模块化
JavaScript天生不支持模块化,如果浏览器需要模块化那么需要引入第三方库- require.js AMD 异步- sea.js CMD异步上面两中都是浏览器模块化规范- common.js common 同步规范当然还有UMD、es6中的modules
总结
-
Node中我们开启的web服务是一个完全的黑盒子,所有资源都不允许用户来访问,用户可以访问的内容具体由开发人员编写设计为准。
-
在Node中可以把一个url地址处理的非常漂亮