nodejs-commonjs模块化、异步、核心库


前言

nodejs入门demo,涉及node模块规范,node的异步编程风格,node核心模块:events、fs、stream、http。


common.js

在编程语言中,每个文件都是一个独立的模块规范,具备独立的作用域,无法在一个文件中访问另一个文件的变量,函数,类等,在node中,采用commonjs规范来解决这一问题。

module和exports

  • moudle其实就是一个对象,module.exports是对外的接口
  • 通过把要导出的变量、函数、类挂到module.exports上,可以实现在其它模块的因引入

require

  • require用于加载模块文件,require读取模块文件,返回该模块的exports对象。如果目标模块没有exports则会报错

自定义模块

module1.js

function sum(a,b) {
  return a + b
}
module.exports = sum

module2.js

function max(a,b) {
  if (a>b) return a
  else return b
}

function min(a,b) {
  if (a<b) return a
  else return b
}
module.exports = { max, min }

main.js

const sum = require('./module1')
const {max, min } = require('./module2')
const math = require('./module2')

console.log(sum(1,2)) // 3
console.log(max(1,2),min(1,2)) // 2 1
console.log(math.max(1,2),math.min(1,2)) // 2 1

commonjs是执行时引入,不参与编译过程,因此将其放入到代码逻辑中也不会报错,这点与ES6 module不同
像下面这样使用也是可以的

const a = 1
const b = 2
if(a===b) {
	const sum = require('./module1')
	console.log(sum(a,b))
} else {
	const { max } = require('./module2')
	console.log(max(a,b))
}

异步编程风格

上篇文章中说过node是采用异步来处理耗时的任务,因此异步在node中无处不在,异步的实现主要有以下三种:

  • 回调函数
  • promise
  • async/await

回调函数

node中扩展的api几乎全部支持回调,但是要明确的是:虽然回调是异步的实现方法,但回调本身和异步并没有任何关系,回调函数是否触发异步取决去事件是否为异步事件
以下是一个回调函数的使用,但他不是异步的

function test(callback){
  console.log('HELLO WORLD')
  callback('HELLO world')
  console.log('hello word')
}
test(function(data){
  console.log(data)
})
console.log('123')
// HELLO WORLD   HELLO world   hello word  123

node中回调函数的语法几乎全部相同,前面的参数为实际需要的param,将错误对象作为回调参数来调用回调函数
以下是一个常用的异步函数,我读取一个不存在的文件,它会异步的给我抛出错误

const fs = require('fs')
fs.readFile('./test.txt',(err,data)=>{
  if (err){
    console.log('error',err)
  } else {
    console.log(data)
  }
})
console.log('123')
/**
123
error [Error: ENOENT: no such file or directory, open 'D:\nodejs\Asynchronous\test.txt'] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: 'D:\\nodejs\\Asynchronous\\test.txt'
}
/

promise

promise是ES6新增的语法规范,用来表示异步操作的最终执行结果

  • 一个promise有三种状态:pending(初始)、fulfilled(成功)、rejected(失败)。pending状态会转为fulfilled或rejected状态,且这个过程不可逆
  • promise接受一个执行函数,该函数接收resolve和reject两个回调函数,分别对应fulfilled和rejected状态对应的函数,进入fulfilled状态时,需要执行resolve函数,否则执行reject函数。
  • promise的then方法和catch方法会返回一个新的promise对象,then方法用来链式调用前一个promise的resove函数,catch则用来捕获reject。then和catch执行正常继续返回resolve,执行过程中出现异常返回reject

promise在使用时可以视为一个异步容器,将要实现的功能放到promise的执行函数中,执行成功和失败时分别调用resolve和reject即可。下面使用promise来改写文件读取函数:

function readFile(file){
  return new Promise((resolve,reject) => {
    fs.readFile('./test.txt',(err,data)=>{
      if (err){
        console.log('error',err)
        reject(err)
      } else {
        console.log(data)
        resolve(data)
      }
    })
  })
}

使用时,到底是触发then方法还是catch方法取决于promise是触发reslove还是reject:

readFile('./test.txt')
.then(data => {
  console.log(data) // 此时的data已经不再是被promise对象包裹的data,而是data本身
})
.catch(err=>{
  console.log(err)
})

async/await

async/await是ES7出现的,对promise的语法糖,它能让异步代码写起来更像同步

  • async和await必须成对出现,async本身会把他后面的内容包装成一个promise
  • await相当于then方法,它会获取resolve状态时的数据,此时拿到的数据不再处于一个promise对象里
    try-catch 相当于ctach方法,他能捕获reject函数触发的异常状态

使用时,到底是触发await方法还是进入catch方法取决于promise是触发reslove还是reject:

async function readFileAsync () {
  try {
    const file = await readFile('./test.txt')
    console.log(file)
  } catch (err) {
    console.log(err)  
  }
}

readFileAsync()

核心模块

nodejs常用的模块很多,这里列举常见的四个:events、fs、stream、http。毫无疑问,每个模块都是通过异步实现。

events

由于node是事件驱动的,因此大多数模块都继承于events,事件模块实现步骤一般分为三步:

  • 创建事件实例
  • 注册事件
  • 触发事件
const EventEmitter = require('events')
// 实例化
const emitter = new EventEmitter()
// 注册事件
emitter.on('click', function(param) {
  console.log('click', param)
})

// once 只触发一次
// emitter.once('click', function(param) {
//   console.log('clickOnce', param)
// })

// 触发事件
emitter.emit('click','hello')
emitter.emit('click','word')

fs

File Syste 是node中用来操作文件的核心模块

函数含义
readFile(path, [,options], callback)读取文件
writeFile(path, content, [,options], callback)写入文件
appendFile(path, content, [,options], callback)文件写入内容
unlink(path, callback)删除文件
mkdir(path, callback)创建文件夹
readdir(path, content, [,options], callback)读取文件夹
rmdir(path, callback)删除文件夹

参数

参数含义
path文件(夹)路径
content文件内容
options可选参数
callback回调函数

举例

const fs = require('fs')
// 读取文件
fs.readFile('./test.txt','utf8', (err,data)=>{
  if (err){
    console.log('error',err)
  } else {
    console.log(data)
  }
})

// 文件写入
fs.readFile('./test.txt','hello word', {encoding:'utf-8'},
(err,data)=>{
  if (err){
    console.log('error',err)
  } else {
    console.log(data)
  }
})

stream

文件IO操作是比较耗时的,所以一般采用stream流的方式进行传输,stream流是EventEmitter的一个实例。http接口的request就是采用stream流进行传输的。

stream有四种常用事件:

  • data: 存在数据可读时触发
  • end: 没有数据读取时触发
  • error: 读取或写入出错时触发
  • finish: 所有数据写入底层时触发

四种类型:

  • Readable:可读
  • Writable: 可写
  • Duplex: 可读可写
  • Transform: 数据转换

stream流操作

名称特征
读取流以小块的方式读取文件,内存占用率低
写入流以小块的方式写入文件
管道从一个流将数据存到另一个流,多个管道可以并行处理,是最常用的方式
数据转换流基于管道,将读取流通过pipe()传入转换流,实现对数据的转换
const fs = require('fs')
const zlib = require('zlib')
//====================创建读取流&写入流==============
const readStream = fs.createReadStream('./fs.js',{ encoding: 'utf-8'}) // 读取文件的stream对象
const writeStream = fs.createWriteStream('./streamOut2.js',{ encoding: 'utf-8'}) // 写入文件的stream对象

//====================读取流&写入流 使用==============
// 文件分块逐个读取写入
readStream.on('data',(chunk)=>{
  writeStream.write(chunk)
})
// 读取完毕 写入完成
readStream.on('end',()=>{
  writeStream.end()
  console.log('write end')
})
// 写入完成
writeStream.on('finish',()=>{
  console.log('write finish')
})
// 读取错误
readStream.on('error',(err)=>{
  console.log('wirte error', err)
})
// 写入错误
writeStream.on('error',(err)=>{
  console.log('wirte error', err)
})

//====================管道流 使用==============
readStream.pipe(writeStream) // 使用管道

writeStream.on('finish',()=>{
  console.log('pipe write finish')
})

//====================转换流 使用==============
fs.createReadStream('./events.js',{ encoding: 'utf-8'})  // 创建文件读取流
  .pipe(zlib.createGzip())  // 创建gzip转换流
  .pipe(fs.createWriteStream('events.js.gz')) // 写入流

http

http模块用于创建http服务器并处理请求,http分为和客户端和服务端

  • http客户端:向目标地址发送请求,回调一个读取流函数
  • http服务端

客户端我以请求自己博客的一张图片并保存至本地为例

const fs = require('fs')
const https = require('https')

const req = https.request('https://img-blog.csdnimg.cn/b75770b282224c5c9858740eb83ab2c7.png#pic_center',
  (res)=>{
    console.log(res.statusCode)
    res.pipe(fs.createWriteStream('./bolg.png'))
  }
)

req.end()

服务端使用http内置模块做个简单示例

const http = require('http')

const server = http.createServer((req,res)=>{
  res.end(JSON.stringify(req.headers))
})

server.listen(8899, () => console.log('listen on 8899'))

打开http://localhost:8899/接口,页面内容如下
在这里插入图片描述

总结

  • node模块化 ——common.js
  • 异步编程风格——回调、promis、async/await
  • node核心模块——events、fs、stream、http
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值