nodejs学习笔记

https://brucecai55520.gitee.io/bruceblog/notes/nodejs/node.html#%E5%88%9D%E8%AF%86-nodejs
先安装node和vscode 工具不再赘述可自行百度安装

bff层

bff浏览器和后台的中间渲染层,为前端服务的后台服务

  • 对前端提供HTTP服务
  • 使用后端的RPC服务
  • 后续更新

第一个nodejs小游戏

nodejs的全局变量会跟浏览器的全局变量有一些差别 大部分像Date, Math, setTimeout这种是一样的
但是例如requestAnimationFrame(在浏览器的下一个帧之后执行)这个是在浏览器中才有的全局变量

// 当前运行的脚本所在的文件路径
console.log(__filename)
// 当前运行的脚本所在的目录位置
console.log(__dirname)
// 进程对象
console.log(process)
  1. 当前运行的脚本所在的文件路径
    在这里插入图片描述
  2. 当前运行的脚本所在的目录位置

在这里插入图片描述

说明在进程对象中会有很多我们想要的api 例如process.argv可以将用户的行为记录到一个变量中

// 将用户输入行为记载到一个变量中
var playAction = process.argv[process.argv.length - 1]
// 电脑随机数
var random = Math.random() * 3
var computerAction
if (random > 1) {
  computerAction = 'rock'
} else if (random > 2) {
  computerAction = 'scissor'
} else {
  computerAction = 'paper'
}
// 如果电脑出的和用户出的一样就平局,如果不一样分三种赢得情况剩下的就是不赢的
if (computerAction === playAction) {
  console.log('平局')
} else if (computerAction === 'rock' && playAction === 'scissor' || computerAction === 'paper' && playAction === 'rock' || computerAction === 'scissor' && playAction === 'paper') {
  console.log('电脑赢了')
} else {
  console.log('我赢了')
}

CommonJS规范

script标签,如果script标签中有src属性,浏览器会把src中的文件下载下来执行,如果有的话就执行script标签中的代码
缺点:
脚本变多时,需要手动的管理加载顺序
不同脚本之前产生逻辑调用,需要通过全局变量的方式
没有html怎么办

CommonJS模块规范
  1. 如果引入的js文件里面没有导出的话,obj打印出来是一个空对象
var obj = require('./lib.js')
  1. 如果lib.js使用的是exports导出那么引入lib.js的文件可以向lib.js内部添加其他变量
  2. 使用module.exports导出引入该lib.js的文件将不能向lib.js内部添加其他变量

原因: exports变量和外面require对象是同一个引用,修改modules.exports会把exports的变量覆盖掉 会换掉exports的引用(更多深层次的内容建议直接看源码)

用commonjs改造剪刀石头布游戏
需求:如果电脑赢了3次之后就把该进程杀掉
在这里插入图片描述
lib.js

module.exports = function playGame(playerAction) {
  var computerAction
  let random = Math.random() * 3
  if (random > 1) {
    computerAction = 'rock'
  } else if (random > 2) {
    computerAction = 'scissor'
  } else {
    computerAction = 'paper'
  }
  if (computerAction === playerAction) {
    console.log('平局')
  } else if (computerAction === 'rock' && playerAction === 'scissor' || computerAction === 'scissor' && playerAction === 'paper' || computerAction === 'paper' && playerAction === 'rock') {
    console.log('电脑赢了')
    return 0
  } else {
    console.log('你赢了')
    return -1
  }
}

index.js

// 一个剪刀石头布的小游戏
// console.log(process)
const playgame = require('./lib')
// var playerAction = process.argv[process.argv.length - 1]
// 监听进程输入的数据
let count = 0
process.stdin.on('data', e => {
  const playerAction = e.toString().trim()
  const result = playgame(playerAction)
  if (result === -1) {
    count++
  }
  if (count === 3) {
    console.log('不玩了')
    process.exit()
  }
})

命令行输入命令
node index.js
在这里插入图片描述
在这里插入图片描述

这是我的目录
在这里插入图片描述

npm

npm是nodejs的包管理工具
包是别人写的nodejs模块
首先通过npm int声明成一个npm包
淘宝的npm镜像https://npmmirror.com/
cnpm自动使用淘宝的镜像下载包
npm官方文档使用说明:https://docs.npmjs.com/
推荐
在这里插入图片描述

nodejs内置模块

可以直接查看nodejs文档
https://nodejs.org/docs/latest-v12.x/api/
nodejs基于chrome v8引擎的运行环境
在这里插入图片描述

EventEmitter

在这里插入图片描述
观察着模式使用情况
关键在于“不知道被通知者存在”以及 “没有听还能继续下去”

例如上新课程,需要通知学员上新(不知道学生是否在也不知道学生是否可以继续听下去)但是都要在app上进行通知

示例:
index.js

// 监听课程 每三秒向前台推送一次数据 如果数据大于50就不买
const oneObj = require('./lib')
oneObj.addListener('objData', res => {
  if (res.price > 50) {
    console.log('不买')
  }
})

lib.js

// EventEmit
// 观察者模式
// 调用vs抛事件
// 关键在于不知道被通知者存在
// 以及 没有听还能继续下去
// 观察者模式是用来解释两个事件之前的通信
const welcomeListen = require('events').EventEmitter
// 继承一下这个类上面的方法
class WelcomeListen extends welcomeListen {
  constructor() {
    super()
    // 暴漏一个方法给外部监听 并且提供price的参数值
    setInterval(() => {
      this.emit('objData', { price: Math.random() * 100 })
    }, 3000);
  }
}
const exportWelcom = new WelcomeListen
module.exports = exportWelcom

Nodejs异步 非阻塞I-O

I/O即一个系统的输入和输出 Input和Output
阻塞I/O和非阻塞I/O的区别在于系统接收输入再到输出期间,能不能接收其他的输入(就是你在洗衣服的时候除了等待洗衣服完成是否还可以做其他的事情比如等待洗衣服的时候擦桌子)
在这里插入图片描述

console.time()
console.timeEnd()

创建一个npm 文件

npm int
npm i glob
const glob = require('glob')

// glob可以递归调用当前目录的文件名称
// glob.sync无法做其他的事情是一个阻塞I/O
var result
console.time('glob')
result = glob.sync(__dirname + '/**/*')
console.timeEnd('glob')
console.time('glob1')
// 这是一个非阻塞I/O在得到结果的时候可以进行一些其他的输入和输出
glob(__dirname + '/**/*', function (err, res) {
  console.log('got result')
})
console.timeEnd('glob1')
console.log(2 + 2)

在这里插入图片描述

左边是node.js线程(点菜员)右边是其他C++(厨师)

异步编程之callback

interview(function (params) {
  console.log(params)
})
function interview(callback) {
  setTimeout(() => {
    callback('success')
  }, 500);
}

在这里插入图片描述
调用栈
在这里插入图片描述
callback容易造成回调地狱 解决方式有promise async/await

事件循环

这篇文章详细讲了浏览器的事件循环机制和nodejs循环机制的区别
https://www.muzhuangnet.com/show/51554.html
事件循环机制原理的简单代码:

// 每隔200ms刷新依次执行队列中的callback
const eventLoop = {
  queue: [],
  loop() {
    setTimeout(() => {
      while (this.queue.length) {
        const callback = this.queue.shift()
        callback()
      }
    }, 200).bind(this);
  },
  add(params) {
    this.queue.push(params)
  }
}
eventLoop.add(
  setTimeout(() => {
    console.log('1')
  }, 100)
)
eventLoop.add(
  setTimeout(() => {
    console.log('2')
  }, 200)
)

异步编程Promise async/await

三个状态 pending resolve reject

resolve状态后的Promise会回调状态的.then reject状态的Promise会回调状态的.catch
任何一个reject且后面没有被.catch接收的话会返回 都会造成node/浏览器环境的错误
当promise被reject之后会调用第一个catch函数

function interview(params) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() * 2 > 1) {
        resolve('成功')
      } else {
        reject(new Error('3'))
      }
    })
  }, 100);
}
interview().then(res => {
  console.log(res)
}).catch(err => {
  console.log(err, 'jjj')
})

执行.then和.catch都会返回一个新的Promise,这个Promise的状态会根据.then和.catch的回调函数返回的结果来定:
如果回调函数最终是throw,则该Promise是rejected状态
如果回调函数最终是return,则该Promise是resolve状态 如果.then和.catch
return出来的是一个新的Promise 那么这个Promise的状态会和回调函数return的Promise状态保持一致
如果在then里面返回一个新的promise后续的操作都是等这个promise执行完之后再执行

  (function (params) {
    function interview(params) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (Math.random() * 2 > 1) {
            resolve('成功')
          } else {
            reject(new Error('3'))
          }
        })
      }, 100);
    }
    var promise = interview()
    var promise2 = promise.then(res => {
      throw new Error('refuse')
    })
    setTimeout(() => {
      console.log(promise)
      console.log(promise2)
    }, 200);
  })()

在这里插入图片描述
promise2.then回调函数抛出的是失败 所以打印出来是rejected

Promise {<rejected>: Error: refuse
    at <anonymous>:15:13}

一个面试是否成功的案例 ( 如果then或者catch当中返回的是一个Promise对象 那么下一次.then要等该promise对象执行完之后再执行接收的是上一个.then回调函数返回的promise resolve成功的值)
假设有三轮面试 面试成功率有80%

function interview(round) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() > 0.2) {
        resolve(round + '成功')
      } else {
        let error = new Error('fail')
        error.round = round
        reject(error)
      }
    })
  }, 100);
}
var promise = interview(1).then(res => {
  console.log(res)
  return interview(2)
}).then((res) => {
  console.log(res)
  return interview(3)
}).then((res) => {
  console.log(res)
})
  .catch((err) => {
    console.log('第' + err.round + '轮失败')
  })

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
使用async/await改写

(async function () {
  try {
    await interview(1)
    await interview(2)
    await interview(3)
    console.log('success')
  } catch (error) {
    console.log('第' + error.round + '轮失败')
  }
})()

HTTP

简单理解HTTP是简单的请求-响应协议 (浏览器和服务器交互的过程)官方定义
解析进来的HTTP请求报文
返回进来的HTTP响应报文
简单的HTTP服务(http模块具有创建服务和监听端口的能力)

const http = require('http')
http.createServer(function (res, req) {
  console.log(req)
  req.writeHead(200)
  req.end('hello')
}).listen(3000)

我们可以f12看下浏览器抓包 localhost就是我们创建的请求
这个是浏览器自带的
在这里插入图片描述
在这里插入图片描述
启动一个服务显示index.html内容

在这里插入代码片// 一个简单的HTTP服务器 http模块提供了创建服务和监听接口的能力

// fs文件模块
const http = require('http')
const fs = require('fs')
http.createServer(function (req, res) {
  console.log(req.url)
  if (req.url === '/favicon.ico') {
    res.writeHead(200)
    res.end()
    return
  }
  res.writeHead(200)
  // res.end('hello')
  // 读取这个html文件将其返回(如果别人给了你一个html文件你想用服务器运行就可以这么写)
  // 快速在某个目录文件下启动一个静态服务器
  fs.createReadStream(__dirname + '/index.html').pipe(res)
}).listen(3000)

express框架

官网
了解一个框架的好方法

  • 了解它的关键功能
  • 推导出它解决的问题是什么
    优点:易上手 高性能 可扩展
    可以使用选择的各种HTTP使用工具和中间件,快速方便创建强大的API

使用官网的Express生成器创建一个express之后
可以看下这个文件配置监听的端口默认是3000
在这里插入图片描述在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值