Node.js 是什么
- Node.js 不是一门语言,不是库、不是框架,Node.js 是一个 JavaScript 运行时环境,可以解析和执行 JavaScript 代码,以前只有浏览器可以可以解析执行 JavaScript 代码,现在的 JavaScript 可以完全脱离浏览器来运行,一切都归功于:Node.js
- 浏览器中的 JavaScript有EcmaScript,BOM, DOM,Node.js 中的 JavaScript没有 BOM、DOM,
- 在 Node 这个 JavaScript 执行环境中为 JavaScript 提供了一些服务器级别的操作 API
- 例如文件读写
- 网络服务的构建
- 网络通信
- http 服务器
- 等处理。。。
- 构建与 Chrome 的 V8 引擎之上,Google Chrome 的 V8 引擎是目前公认的解析执行 JavaScript 代码最快的,Node.js 的作者把 Google Chrome 中的 V8 引擎移植了出来,开发了一个独立的 JavaScript 运行时环境。
- 特点
- event-driven 事件驱动
- non-blocking I/O model 非阻塞IO模型(异步)
- lightweight and efficient. 轻量和高效
Node.js 能做什么
- Web 服务器后台
- 命令行工具
- npm(node)
- git(c 语言)
- hexo(node)
- 对于前端开发工程师来讲,接触 node 最多的是它的命令行工具
- webpack
- gulp
- npm
本文知识简介
- B/S 编程模型
- Browser - Server
- back-end
- 任何服务端技术这种 BS 编程模型都是一样,和语言无关
- 模块化编程
- RequireJS
- SeaJS
@import('文件路径')
,在 Node 中可以像@import()
一样来引用加载 JavaScript 脚本文件
- Node常用API
- 异步编程
- 回调函数
- Promise
- async
- generator
- Express Web 开发框架
起步
解析执行 JavaScript
- 创建编写 JavaScript 脚本文件
- 打开终端,定位到脚本文件所属目录
- 输入
node 文件名
执行对应的文件
注意:文件名不要使用 node.js
来命名,也就是说除了 node
这个名字你随便起,而且最好也不要使用中文。
文件读写
浏览器中的 JavaScript 是没有文件操作的能力的,但是 Node 中的 JavaScript 具有文件操作的能力
fs 是 file-system 的简写,就是文件系统的意思,在 Node 中如果想要进行文件操作,就必须引入 fs 这个核心模块,在 fs 这个核心模块中,就提供了所有的文件操作相关的 API
javascript
// 1. 使用 require 方法加载 fs 核心模块
var fs = require('fs')
// 2. 读取文件
// 第一个参数就是要读取的文件路径
// 第二个参数是一个回调函数
// 读取成功
// data 等于数据
// error 等于null
// 读取失败
// data 等于undefined没有数据
// error 等于错误对象
fs.readFile('./data/a.txt', function (error, data) {
// 文件中存储的其实都是二进制数据 0 1,
// 可以通过 toString 方法把其转为我们能认识的字符
// console.log(data)
// console.log(error)
// 在这里就可以通过判断 error 来确认是否有错误发生
if (error) {
console.log('读取文件失败了')
} else {
console.log(data.toString())
}
})
文件写入:
javascript
var fs = require('fs')
// 第一个参数:文件路径
// 第二个参数:文件内容
// 第三个参数:回调函数
// error:
// 文件写入成功,error 是 null
// 文件写入失败,error 就是错误对象
fs.writeFile('./data/你好.md', '大家好,给大家介绍一下,我是Node.js', function (error) {
// console.log(error)
if (error) {
console.log('写入失败')
} else {
console.log('写入成功了')
}
})
http
在 Node 中专门提供了一个核心模块:http,这个模块的职责就是帮你创建编写服务器的
javascript
// 1. 加载 http 核心模块
var http = require('http')
// 2. 使用 http.createServer() 方法创建一个 Web 服务器
// 返回一个 Server 实例
var server = http.createServer()
// 3. 服务器要干嘛?提供服务:数据的服务;发请求;接收请求;处理请求;发送响应
// 注册 request 请求事件
// 当客户端请求过来,就会自动触发服务器的 request 请求事件,然后执行第二个参数:回调处理函数
server.on('request', function () {
console.log('收到客户端的请求了')
})
// 4. 绑定端口号,启动服务器
server.listen(3000, function () {
console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
})
Node 中的 JavaScript
- EcmaScript 语言
- 和浏览器不一样,在 Node 中没有 BOM、DOM
- 核心模块
- 文件操作的 fs
- http 服务的 http
- url 路径操作模块
- path 路径处理模块
- os 操作系统信息
- 第三方模块
- art-template
- 必须通过 npm 来下载才可以使用
- 自己写的模块
- 自己创建的文件
EcmaScript
核心模块
Node 为 JavaScript 提供了很多服务器级别的 API ,这些 API 绝大多数都被包装到了一个具名的核心模块中了。例如文件操作的 fs
核心模块,http 服务构建的 http
模块,path
路径操作模块、os
操作系统信息模块。如果想要使用它,就必须先使用 require
方法加载才能使用:
javascript
var fs = require('fs')
var http = require('http')
ip 地址和端口号
- ip 地址用来定位计算机
- 端口号用来定位具体的应用程序,一切需要联网通信的软件都会占用一个端口号,端口号的范围从 0 - 65536 之间。在计算机中有一些默认端口号,最好不要去使用,例如 http 服务的 80
- 我们在开发过程中使用一些简单好记的端口号就可以了,例如 3000、5000 等没什么含义
- 可以同时开启多个服务,但一定要确保不同服务占用的端口号不一致才可以,即在一台计算机中,同一个端口号同一时间只能被一个程序占用
在 Node 中使用模板引擎
安装:
shell
$ npm install art-template
使用:
javascript
var template = require('art-template')
var ret = template.render('hello {{ name }}', {
name: 'Jack'
})
console.log(ret) // => hello Jack
CommonJS 模块规范
在 Node 中的 JavaScript 还有一个很重要的概念:模块系统。
- 模块作用域
- 使用 require 方法用来加载模块
- 使用 exports 接口对象用来导出模块中的成员
加载 require
语法:
javascript
var 自定义变量名称 = require('模块')
两个作用:
- 执行被加载模块中的代码
- 得到被加载模块中的
exports
导出接口对象
导出 exports
- Node 中是模块作用域,默认文件中所有的成员只在当前文件模块有效
- 对于希望可以被其它模块访问的成员,我们就需要把这些公开的成员都挂载到
exports
接口对象中就可以了
导出多个成员(必须在对象中):
javascript
exports.a = 123
exports.b = 'hello'
exports.c = function () {
console.log('ccc')
}
exports.d = {
foo: 'bar'
}
导出多个成员也可以这么来写:
javascript
module.exports = {
foo: 'bar',
add: function () {
}
}
导出单个成员(拿到的就是:函数、字符串):
javascript
module.exports = 'hello'
以下情况会覆盖:
javascript
module.exports = 'hello'
// 以这个为准,后者会覆盖前者
module.exports = function (x, y) {
return x + y
}
也可以这样来导出多个成员:
javascript
module.exports = {
add: function () {
return x + y
},
str: 'hello'
}
原理解析
exports 和 module.exports
的一个引用:
javascript
// var module = {
// exports = {}
// }
// var exports = module.exports
console.log(exports === module.exports) // => true
exports.foo = 'bar'
// 等价于
moudle.exports.foo = 'bar'
// return module.exports
exports 和 module.exports 的区别
- exports 和 module.exports 的区别
- 每个模块中都有一个 module 对象,module 对象中有一个 exports 对象, 我们可以把需要导出的成员都挂载到 module.exports 接口对象中 也就是:
moudle.exports.xxx = xxx
的方式 - 但是每次都
moudle.exports.xxx = xxx
很麻烦,所以 Node 为了你方便,同时在每一个模块中都提供了一个成员叫:exports
exports === module.exports
结果为true
所以对于: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
这个用来重新建立引用关系的
- 每个模块中都有一个 module 对象,module 对象中有一个 exports 对象, 我们可以把需要导出的成员都挂载到 module.exports 接口对象中 也就是:
require 方法加载规则
- 优先从缓存加载
- 判断模块标识
- 核心模块
- 第三方模块
- 自己写的模块
-
路径形式的模块:
./ 当前目录,不可省略
.../ 上一级目录,不可省略
/xxx 几乎不用 (首位的 / 在这里表示的是当前文件模块所属磁盘根路径)
d:/a/foo.js 几乎不用
.js 后缀名可以省略require('./foo.js')
-
核心模块的本质也是文件,核心模块文件已经被编译到了二进制文件中了,我们只需要按照名字来加载就可以了
require('fs') require('http')
-
第三方模块
凡是第三方模块都必须通过 npm 来下载
使用的时候就可以通过 require('包名') 的方式来进行加载才可以使用
不可能有任何一个第三方包和核心模块的名字是一样的
加载art-template示例:找到node_modules/art-template/package.json 文件中的 main 属性,main 属性中就记录了 art-template 的入口模块,然后加载使用这个第三方包
如果 package.json 文件不存在或者 main 指定的入口模块是也没有,则 node 会自动找该目录下的 index.js,也就是说 index.js 会作为一个默认备选项
如果以上所有任何一个条件都不成立,则会进入上一级目录中的node_modules 目录查找,如果上一级还没有,则继续往上上一级查找, 如果直到当前磁盘根目录还找不到,最后报错:can not find module xxx
var template = require('art-template')
npm 命令行工具
npm 也有版本这个概念。
shell
npm --version
升级 npm(自己升级自己):
shell
npm install --global npm
常用命令
npm init
- npm init -y 可以跳过向导,快速生成
npm install
- 一次性把 dependencies 选项中的依赖项全部安装
- npm i
npm install 包名
- 只下载
- npm i 包名
npm install --save 包名
- 下载并且保存依赖项(package.json 文件中的 dependencies 选项)
- npm i -S 包名
npm uninstall 包名
- 只删除,如果有依赖项会依然保存
- npm un 包名
npm uninstall --save 包名
- 删除的同时也会把依赖信息也去除
- npm un -S 包名
npm help
- 查看使用帮助
npm 命令 --help
- 查看指定命令的使用帮助
- 例如我忘记了 uninstall 命令的简写了,这个时候,可以输入
npm uninstall --help
来查看使用帮助
解决 npm 被墙问题
npm 存储包文件的服务器在国外,有时候会被墙,速度很慢,所以我们需要解决这个问题。
http://npm.taobao.org/ 淘宝的开发团队把 npm 在国内做了一个备份。
安装淘宝的 cnpm:
shell
# 在任意目录执行都可以
# --global 表示安装到全局,而非当前目录
# --global 不能省略,否则不管用
npm install --global cnpm
接下来你安装包的时候把之前的 npm
替换成 cnpm
。
举个例子:
shell
# 这里还是走国外的 npm 服务器,速度比较慢
npm install jquery
# 使用 cnpm 就会通过淘宝的服务器来下载 jquery
cnpm install jquery
如果不想安装 cnpm
又想使用淘宝的服务器来下载:
shell
npm install jquery --registry=https://registry.npm.taobao.org
但是每一次手动这样加参数很麻烦,所我们可以把这个选项加入配置文件中:
shell
# 配置到淘宝服务器
npm config set registry https://registry.npm.taobao.org
# 查看 npm 配置信息
npm config list
只要经过了上面命令的配置,则你以后所有的 npm install
都会默认通过淘宝的服务器来下载。
package.json
建议每一个项目都要有一个 package.json
文件(包描述文件,就像产品的说明书一样),这个文件可以通过 npm init
的方式来自动初始化出来。
package.json中的 dependencies
选项,可以用来帮我们保存第三方包的依赖信息。这样如果你的 node_modules
删除了也不用担心,只需要:npm install
就会自动把 package.json
中的 dependencies
中所有的依赖项都下载回来。
- 建议每个项目的根目录下都有一个
package.json
文件 - 建议执行
npm install 包名的
的时候都加上--save
这个选项,目的是用来保存依赖项信息
package.json 和 package-lock.json
npm 5 以前是不会有 package-lock.json
这个文件的,npm 5 以后才加入了这个文件,当你安装包的时候,npm 都会生成或者更新 package-lock.json
这个文件。
- npm 5 以后的版本安装包不需要加
--save
参数,它会自动保存依赖信息 - 当你安装包的时候,会自动创建或者是更新
package-lock.json
这个文件 package-lock.json
这个文件会保存node_modules
中所有包的信息(版本、下载地址),这样的话重新npm install
的时候速度就可以提升- 从文件来看,有一个
lock
称之为锁,这个lock
是用来锁定版本的。如果项目依赖了1.1.1
版本,没有package-lock时重新 install 其实会下载最新版本,而不是 1.1.1,有package-lock可以锁住 1.1.1 这个版本,防止自动升级新版
Express
原生的 http 在某些方面表现不足以应对我们的开发需求,所以我们就需要使用框架来加快我们的开发效率,框架的目的就是提高效率,让我们的代码更高度统一。
安装
shell
npm install --save express
hello world
javascript
const express = require('express')
const app = express()
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(3000, () => console.log('Example app listening on port 3000!'))
基本路由
- 请求方法
- 请求路径
- 请求处理函数
get:
javascript
// 当你以 GET 方法请求 / 的时候,执行对应的处理函数
app.get('/', function (req, res) {
res.send('Hello World!')
})
post:
javascript
// 当你以 POST 方法请求 / 的时候,指定对应的处理函数
app.post('/', function (req, res) {
res.send('Got a POST request')
})
静态服务
javascript
// /public资源
app.use(express.static('public'))
// /files资源
app.use(express.static('files'))
// /public/xxx
app.use('/public', express.static('public'))
// /static/xxx
app.use('/static', express.static('public'))
app.use('/static', express.static(path.join(__dirname, 'public')))
配置 art-template
模板引擎
安装:
shell
npm install --save art-template
npm install --save express-art-template
配置:
javascript
// 第一个参数用来配置视图的后缀名,这里是 art ,则你存储在 views 目录中的模板文件必须是 xxx.art
// app.engine('art', require('express-art-template'))
// 这里我把 art 改为 html
app.engine('html', require('express-art-template'))
使用:
javascript
app.get('/', function (req, res) {
// express 默认会去项目中的 views 目录找 index.html
res.render('index.html', {
title: 'hello world'
})
})
如果希望修改默认的 views
视图渲染存储目录,可以:
javascript
// 注意:第一个参数 views 千万不要写错
app.set('views', 目录路径)
在 Express 中获取表单 GET 请求参数
Express 内置了一个 API,可以直接通过 req.query
来获取
javascript
req.query
在 Express 获取表单 POST 请求体数据
在 Express 中没有内置获取表单 POST 请求体的 API,这里我们需要使用一个第三方包:body-parser
。
安装:
shell
npm install --save body-parser
配置:
javascript
var express = require('express')
// 0. 引包
var bodyParser = require('body-parser')
var app = express()
// 配置 body-parser
// 只要加入这个配置,则在 req 请求对象上会多出来一个属性:body
// 也就是说你就可以直接通过 req.body 来获取表单 POST 请求体数据了
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
使用:
javascript
app.use(function (req, res) {
res.setHeader('Content-Type', 'text/plain')
res.write('you posted:\n')
// 可以通过 req.body 来获取表单 POST 请求体数据
res.end(JSON.stringify(req.body, null, 2))
})
路由设计
请求方法 | 请求路径 | get 参数 | post 参数 | 备注 |
---|---|---|---|---|
GET | /studens | 渲染首页 | ||
GET | /students/new | 渲染添加学生页面 | ||
POST | /studens/new | name、age、gender、hobbies | 处理添加学生请求 | |
GET | /students/edit | id | 渲染编辑页面 | |
POST | /studens/edit | id、name、age、gender、hobbies | 处理编辑请求 | |
GET | /students/delete | id | 处理删除请求 |
提取路由模块
router.js:
javascript
/**
* router.js 路由模块
* 职责:
* 处理路由
* 根据不同的请求方法+请求路径设置具体的请求处理函数
* 模块职责要单一,不要乱写
* 我们划分模块的目的就是为了增强项目代码的可维护性
* 提升开发效率
*/
var express = require('express')
// 1. 创建一个路由容器
var router = express.Router()
// 2. 把路由都挂载到 router 路由容器中
router.get('/students', function (req, res) {
})
router.get('/students/new', function (req, res) {
})
router.post('/students/new', function (req, res) {
})
router.get('/students/edit', function (req, res) {
})
router.post('/students/edit', function (req, res) {
})
router.get('/students/delete', function (req, res) {
})
// 3. 把 router 导出
module.exports = router
app.js:
javascript
var router = require('./router')
// 挂载路由
app.use(router)
设计操作数据的 API 文件模块
javascript
/**
* student.js
* 数据操作文件模块
* 职责:操作文件中的数据,只处理数据,不关心业务
*/
/**
* 获取所有学生列表
* return []
*/
exports.find = function () {
}
/**
* 添加保存学生
*/
exports.save = function () {
}
/**
* 更新学生
*/
exports.update = function () {
}
/**
* 删除学生
*/
exports.delete = function () {
}
自己编写的步骤
- 处理模板
- 配置开放静态资源
- 配置模板引擎
- 简单路由:/students 渲染静态页出来
- 路由设计
- 提取路由模块
- 由于接下来一些列的业务操作都需要处理文件数据,所以我们需要封装 student.js
- 先写好 student.js 文件结构
- 查询所有学生列表的 API find
- findByid
- save
- updateById
- deleteById
- 实现具体功能
- 通过路由收到请求
- 接收请求中的数据(get、post)
- req.query
- req.body
- 调用数据操作 API 处理数据
- 根据操作结果给客户端发送响应
- 业务功能顺序
- 列表
- 添加
- 编辑
- 删除
- find
- findIndex
MongoDB
关系型数据库和非关系型数据库
表就是关系
或者说表与表之间存在关系。
- 所有的关系型数据库都需要通过
sql
语言来操作 - 所有的关系型数据库在操作之前都需要设计表结构
- 而且数据表还支持约束
- 唯一的
- 主键
- 默认值
- 非空
- 非关系型数据库非常的灵活
- 有的非关系型数据库就是 key-value 对儿
- 但是 MongoDB 是长的最想关系型数据库的非关系型数据库
- 数据库 -》数据库
- 数据表-》集合(数组)
- 表记录-》(文档对象)
- MongoDB 不需要设计表结构
- 也就是说你可以任意的往里面存数据,没有结构性这么一说
安装
- 下载
- 安装
- 配置环境变量
- 最后输入
mongod --version
测试是否安装成功
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EdiOHG2d-1589879868803)(media/1509940577391.png)]
启动和关闭数据库
启动:
shell
# mongodb 默认使用执行 mongod 命令所处盘符根目录下的 /data/db 作为自己的数据存储目录
# 所以在第一次执行该命令之前先自己手动新建一个 /data/db
mongod
如果想要修改默认的数据存储目录,可以:
shell
mongod --dbpath=数据存储目录路径
停止:
在开启服务的控制台,直接 Ctrl+c 即可停止。
或者直接关闭开启服务的控制台也可以。
连接和退出数据库
连接:
shell
# 该命令默认连接本机的 MongoDB 服务
mongo
退出:
shell
# 在连接状态输入 exit 退出连接
exit
基本命令
show dbs
- 查看显示所有数据库
db
- 查看当前操作的数据库
use 数据库名称
- 切换到指定的数据(如果没有会新建)
- 插入数据
mongoose
官方的 mongodb
包来操作:https://github.com/mongodb/node-mongodb-native
第三方包:mongoose
基于 MongoDB 官方的 mongodb
包再一次做了封装。
异步编程
回调函数
不成立的情况:
javascript
function add(x, y) {
console.log(1)
setTimeout(function () {
console.log(2)
var ret = x + y
return ret
}, 1000)
console.log(3)
// 到这里执行就结束了,不会等到前面的定时器,所以直接就返回了默认值 undefined
}
console.log(add(10, 20)) // => undefined
不成立的情况:
javascript
function add(x, y) {
var ret
console.log(1)
setTimeout(function () {
console.log(2)
ret = x + y
}, 1000)
console.log(3)
return ret
}
console.log(add(10, 20)) // => undefined
回调函数:
如果我讲到这种程度了,说明一个问题,没有认知能力()
如何熟练达到像定义一个变量一样来封装一个带有回调函数的方法。
主要原因在于写得少,这是 JavaScript 编程的一大特色:异步编程。
甚至很多具有服务端开发经验的都不太容易熟悉这种方式。
javascript
function add(x, y, callback) {
// callback 就是回调函数
// var x = 10
// var y = 20
// var callback = function (a) { }
console.log(1)
setTimeout(function () {
var ret = x + y
callback(ret)
}, 1000)
}
add(10, 20, function (a) {
// a 才是我们得到的结果
})
基于原生 XMLHTTPRequest 封装 get 方法:
javascript
function get(url, callback) {
var oReq = new XMLHttpRequest()
// 当请求加载成功之后要调用指定的函数
oReq.onload = function () {
// 我现在需要得到这里的 oReq.responseText
callback(oReq.responseText)
}
oReq.open("get", url, true)
oReq.send()
}
get('data.json', function (data) {
console.log(data)
})
Promise
callback hell:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-622wlEhO-1589879868805)(media/1509967270775.png)]
无法保证顺序的代码:
javascript
var fs = require('fs')
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
})
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
})
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
})
通过回调嵌套的方式来保证顺序:
javascript
var fs = require('fs')
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
})
})
})
为了解决以上编码方式带来的问题(回调地狱嵌套),所以在 EcmaScript 6 中新增了一个 API:Promise
。
- Promise 的英文就是承诺、保证的意思(I promise you)
Promise 基本语法:
javascript
var fs = require('fs')
// 在 EcmaScript 6 中新增了一个 API Promise
// Promise 是一个构造函数
// 创建 Promise 容器
// 1. 给别人一个承诺 I promise you.
// Promise 容器一旦创建,就开始执行里面的代码
var p1 = new Promise(function (resolve, reject) {
// console.log(2)
fs.readFile('./data/aa.txt', 'utf8', function (err, data) {
if (err) {
// 失败了,承诺容器中的任务失败了
// console.log(err)
// 把容器的 Pending 状态变为 Rejected
// 调用 reject 就相当于调用了 then 方法的第二个参数函数
reject(err)
} else {
// console.log(3)
// 承诺容器中的任务成功了
// console.log(data)
// 把容器的 Pending 状态改为成功 Resolved
// 也就是说这里调用的 resolve 方法实际上就是 then 方法传递的那个 function
resolve(data)
}
})
})
// console.log(4)
// p1 就是那个承若
// 当 p1 成功了 然后(then) 做指定的操作
// then 方法接收的 function 就是容器中的 resolve 函数
p1
.then(function (data) {
console.log(data)
}, function (err) {
console.log('读取文件失败了', err)
})
封装 Promise 版本的 readFile
:
javascript
var fs = require('fs')
function pReadFile(filePath) {
return new Promise(function (resolve, reject) {
fs.readFile(filePath, 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}
pReadFile('./data/a.txt')
.then(function (data) {
console.log(data)
return pReadFile('./data/b.txt')
})
.then(function (data) {
console.log(data)
return pReadFile('./data/c.txt')
})
.then(function (data) {
console.log(data)
})
其它
代码风格
- Airbnb JavaScript Style
- 更专业规范,比较严谨
- JavaScript Standard Style
- 符合大多数人的习惯
规范只是建议,可以遵守也可以不遵守,在一些比较专业的团队中,对于代码风格会有对应的风格校验工具,如果你的代码风格有问题,例如少了一个空格或者多了一个空格,你的代码都是不允许提交的。
后面会学习如何使用工具来强制校验代码风格的问题。
代码无分号问题
无论你是否使用的是无分号的代码风格规范,都建议当一行代码是以:
(
[
- `
以上三者开头的的时候,最好都在其之前补上一个分号。
例如:
javascript
;(function () {
// code here
})()
修改完代码自动重启
我们这里可以使用一个第三方命名航工具:nodemon
来帮我们解决频繁修改代码重启服务器问题。
nodemon
是一个基于Node.js 开发的一个第三方命令行工具,我们使用的时候需要独立安装:
shell
# 在任意目录执行该命令都可以
# 也就是说,所有需要 --global 来安装的包都可以在任意目录执行
npm install --global nodemon
安装完毕之后,使用:
shell
node app.js
# 使用 nodemon
nodemon app.js
只要是通过 nodemon app.js
启动的服务,则它会监视你的文件变化, 当文件发生变化的时候,自动帮你重启服务器。
文件操作路径和模块路径
文件操作路径:
// 在文件操作的相对路径中
// ./data/a.txt 相对于当前目录
// data/a.txt 相对于当前目录
// /data/a.txt 绝对路径,当前文件模块所处磁盘根目录
// c:/xx/xx... 绝对路径
// fs.readFile('./data/a.txt', function (err, data) {
// if (err) {
// console.log(err)
// return console.log('读取失败')
// }
// console.log(data.toString())
// })
模块操作路径:
// 这里如果忽略了 . 则也是磁盘根目录
require('/data/foo.js')
// 相对路径
require('./data/foo.js')
// 模块加载的路径中的相对路径不能省略 ./