node
组成
- ECMAScript
- Node模块API
运行js文件
node xxx
模块化开发
Node.js规定一个JavaScript文件就是一个模块,模块内部定义的变量和函数默认情况下在外部无法得到模块内部可以使用exports对象进行成员导出, 使用require方法导入其他模块
js开发弊端
- 文件依赖
- 命名冲突
模块导出
// module.jsexports.add= (a,b) => a+b// 另外一种导出方式module.exports.add = (a,b) => a+b;// exports是module.exports的别名(地址引用关系),当它们指向的部署同一个对象时,导出对象最终以module.exports为准
模块导入
// other.jslet demo = require('./module');demo.add(1,2);
系统模块
fs
const fs = require('fs')// 读取文件fs.readFile('./index.html',(err,doc)=>{ if (!err){ console.log(doc.toString()) }})// 文件写入fs.writeFile('test.txt','run it',error => { console.log(error);})
path
const path = require('path')// 拼接路径console.log(path.join(__dirname,'TMP','MY')) // windows: C:\Users\MY\TMP\web\TMP\MY// 大多数情况下使用绝对路径,因为相对路径有时候相对的是命令行工具的当前工作目录
第三方模块
npm install xx # 安装模块(本地安装)npm uninstall xx # 卸载模块npm install xx -g # 全局安装
nodemon
能监控文件的变化,变化时自动运行它
npm install nodemon -g # 安装nodemon test # 使用nodemon代替node执行js文件,当js文件发生变更后,会自动重新运行js文件
nrm
npm下载地址切换工具
nrm ls # 列出可用源nrm use xx # 使用某个源
gulp
npm install gulpnpm install gulp-cli -g
// 执行 gulp firstconst gulp = require('gulp');gulp.task('first', () => { return gulp.src('./src/index.html') .pipe(gulp.dest('./dist'))})
插件
- 使用
// 压缩htmlconst htmlmin = require('gulp-htmlmin')gulp.task('htmlmin', () => { return gulp.src('./src/*.html') .pipe(htmlmin({collapseWhitespace:true})) .pipe(gulp.dest('./dist'))})
全局对象
- global
package.json
项目描述文件,记录了当前项目信息,例如项目名称、版本、作者、github地址、 当前项目依赖了哪些第三方模块等。
使用npm init -y
命令生成。
- dependencies
- devDependencies
- package-lock.json
- 锁定包的版本
- 记录了包以及依赖的下载地址
script
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build":"nodemon a.js" }
npm run build
模块加载机制
// 如果模块后缀省略,先找同名JS文件再找同名JS文件夹// 如果找到了同名文件夹,找文件夹中的index.js// 如果文件夹中没有index.js就会去当前文件夹中的package.js文件中查找main选项中的入口文件// 如果再找不到就抛出异常require('./xx')// Node.js会假设它是 系统模块// Node.js会去node_ modules文件夹中// 首先看是否有该名字的JS文件// 再看是否有该名字的文件夹// 如果是文件夹看里面是否有index.js// 如果没有index.js查看 该文件夹中的package.json中的main选项确定模块入口文件// 否则找不到报错require('xx')
异步编程
- 同步api
- 会阻塞
- 从返回值拿执行结果
- 异步api
- 不会阻塞
- 从回调函数拿执行结果
代码执行顺序
console.log('代码开始执行');setTimeout(() => { console.log('2秒后执行的代码');}, 2000); setTimeout(() => { console.log('"0秒"后执行的代码');}, 0);console.log('代码结束执行');
Promise
- 解决异步编程问题
Promise 是一个对象,它代表了一个异步操作的最终完成或者失败
var promise = new Promise((resolve, reject) => { setTimeout(function () { let condition = true; if (condition) { resolve('foo'); // 回调then里的函数 } else { reject('error'); // 回调catch里的函数 } }, 300);});promise .then(value => { console.log(value); }) .catch(error => { console.log(error) })
- 解决回调地狱
promise .then(v=>{ // 如果返回Promise,则这个promise是调用下一个then的promise // 如果不是promise,则就是下一个then的回调函数参数v return new Promise() }) .then(v=>{ return new Promise() })
all与race
// 所有任务都完成才返回结果Promise.all([query(),query(),query()]).then(()=>console.log('all mission complete'));// 任一任务都完成就返回结果Promise.race([query(),query(),query()]).then(()=>console.log('mission complete'));
错误捕获
Promise 对象的错误,会一直向后传递,直到被 onReject 函数处理或 catch 语句捕获为止
异步函数
// 使用async修饰,这个函数会返回一个Promiseconst fn = async () => {};async function fn () {}
async function f() { return 11;}f() .then(v=>console.log(v))
- await
await关键字只能出现在异步函数中
await关键字可暂停异步函数向下执行 直到promise返回结果
async function f1() { return 11;}async function f2(){ return 22;}async function f(){ // 可以通过await关键字将异步函数转同步执行 let i1 = await f1(); let i2 = await f2(); console.log(i1,i2)}f()
一个被 async 修饰的函数会被包装为一个 Promise,遇到await关键字时,引擎会把该任务提交给微任务队列,然后暂停当前协程的执行,将主线程的控制权转交给父协程执行,同时会将await的这个对象返回给父协程,父协程拿到这个对象之后,就是调用then方法了
web服务器
创建
var http = require('http')http.createServer((request,response)=>{ const body = "hello world"; response.writeHead(200,{ 'Content-Length':Buffer.byteLength(body), 'Content-Type':'text/plain' }); response.end(body);}).listen(8888);
请求报文
const body = `request method:${request.method} request url:${request.url} request headers ua:${request.headers["user-agent"]}`
响应报文
response.writeHead(200,{ 'Content-Type':'application/json'})response.end('{"result":"25"}')
请求参数
- get
const url = require('url')let { query } = url.parse(request.url, true)// 输出name参数与age参数response.end(query.name + "," + query.age)
- post
let postData = ''request.on('data',params=>{ postData += params})request.on('end',()=>{ let i = querystring.parse(postData) response.end(`name: ${i.name} address: ${i.address}`)})
路由
let { pathname } = url.parse(req.url);if (pathname == '/' || pathname == '/index') { response.end('欢迎来到首页');} else if (pathname == '/list') { response.end('欢迎来到列表页页');} else { response.end('抱歉, 您访问的页面出游了');}
静态资源
fs.readFile(__dirname+'/static'+pathname,(error,data)=>{ if (!error){ let type = pathname.substring(pathname.lastIndexOf('.')+1) response.writeHead(200,{ "Content-Type":mime.getType(pathname) }) response.end(data) }else{ response.writeHead(404,{ "Content-Type":"text/html;charset=utf8" }) response.end('404 NOT FOUND') }})