别催了~ 正在从服务器偷取页面 . . .

node学习


基础知识

从命令行接受输入

readline模块可以每次一行地从可读流(例如 process.stdin 流)获取输入。

const readline = require('readline').createInterface({
  input: process.stdin,
  output: process.stdout
})

readline.question(`你叫什么名字?`, name => {
  console.log(`你好 ${name}!`)
  readline.close()
})

Node模块规范

Node中模块用的是CommonJS规范,有以下两种使用方式:

//导出的文件中
function sum(a,b){
  return a+b;
}
//方式一
exports.sum=sum;
//导出方式二
module.exports = {
    sum,
    ...
};
  
 //导入的文件
 const sum=require("...")//文件路径
  • CommonJS 以同步的方式加载模块。这一点其实可以理解,因为 Node 通常是运行于服务端,而在服务端模块文件通常存放在本地磁盘,读取速度比起前端通过网络下载要快得多,所以一般没有什么问题(但是因此也不适用于前端)
  • CommonJS 输出的是模块的拷贝,这一点与 ESNext 模块不同。模块一旦输出后便独立(即后续更改不影响)
  • Node 中对引入过的模块都会进行缓存,减少后续引入的开销。

nodejs常用内置模块

  • fs ,文件操作模块,例如fs.readFile(异步读取文件)、fs.readFileSync(同步读取文件)
  • http ,网络操作模块,用于创建服务器。如 http.createServer
  • path ,路径操作模块,用于获取和处理文件路径
  • url ,url 模块,主要是一些操作url的API,例如url解析

Buffer数据类型

Node.js 中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区,Buffer 类似于一个整数数组。

let buf1 = Buffer.from([97, 98, 99]);  //根据一个数组创建 Buffer 对象
console.log(buf1);  //<Buffer 61 62 63> 以16进制存在buffer对象中
console.log(buf1.toString());

let buf2 = Buffer.from("nodejs");   //根据一个字符串创建 Buffer 对象
console.log(buf2);
console.log(buf2.toString());

let buf3 = Buffer.alloc(10);   // 创建了可以存放10个字符的buffer对象
buf3.write("abc");  //按照ASCII表的值,转16进制,存在buffer中
console.log(buf3);
console.log(buf3.toString());

//<Buffer .....  > 需要  toString()   才能看到里面的真实数据

两个文件

package.json文件

package.json 是项目描述文件,保存在项目的根目录下面,记录了当前的项目信息,用npm init -y命令生成
例子如下:

{
  "name": "plant",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "axios": "^0.26.1",
    "core-js": "^3.6.5",
    "echarts": "^5.3.3",
    "echarts-gl": "^2.0.9",
    "element-plus": "^2.1.0",
    "esri-loader": "^3.4.0",
    "postcss-px2rem": "^0.3.0",
    "qs": "^6.10.3",
    "sass": "^1.26.5",
    "sass-loader": "^7.3.1",
    "sass-resources-loader": "^2.2.5",
    "vue": "^3.0.0",
    "vue-amap": "^0.5.10",
    "vue-axios": "^3.4.1",
    "vue-router": "^4.0.0-0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.15",
    "@vue/cli-plugin-eslint": "~4.5.15",
    "@vue/cli-plugin-router": "~4.5.15",
    "@vue/cli-service": "~4.5.15",
    "@vue/compiler-sfc": "^3.0.0",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^7.0.0"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/vue3-essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "babel-eslint"
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}
  • version 表明了当前的版本。

  • name 设置了应用程序/软件包的名称。

  • description 是应用程序/软件包的简短描述。

  • main 设置了应用程序的入口点。

  • private 如果设置为 true,则可以防止应用程序/软件包被意外地发布到 npm。

  • scripts 定义了一组可以运行的 node 脚本。

  • dependencies 设置了作为依赖安装的 npm 软件包的列表。

  • devDependencies 设置了作为开发依赖安装的 npm 软件包的列表。

  • engines 设置了此软件包/应用程序在哪个版本的 Node.js 上运行。

  • browserslist 用于告知要支持哪些浏览器(及其版本)。

    package-lock.json 文件

  • 记录模块与模块之间的依赖关系

  • 锁定包的版本

  • 记录项目所依赖第三方包的树状结构和包的下载地址,加快重新安装的下载速度

    其他

  • NODE_ENV是一个环境变量,NODE_ENV=“production”表示在开发环境执行代码,NODE_ENV=”development”表示在生产环境执行代码

  • stream pipe(流),Node中可以使用流进行数据输入输出(特别是当响应数据是大文件时,可以提高传送效率)

Node重点

事件循环

什么是事件循环?

  1. 事件循环类型像while循环那样,每执行一次循环体就称为一个Tick,每个 Tick 的过程就是查看是否有事件待处理。如果有就取出事件及其相关的回调函数,然后进入下一个循环,如果不再有事件处理,就退出进程。
  2. Node的事件循环机制和浏览器是不同的。
  3. 这些事件主要是网络请求、文件I/O等等

    EventLoop

    Eventloop就是一个循环的一个Tick
    先上Eventloop图:
       ┌───────────────────────────┐
    ┌─>│           timers          │
    │  └─────────────┬─────────────┘
    │  ┌─────────────┴─────────────┐
    │  │     pending callbacks     │
    │  └─────────────┬─────────────┘
    │  ┌─────────────┴─────────────┐
    │  │       idle, prepare       │
    │  └─────────────┬─────────────┘      ┌───────────────┐
    │  ┌─────────────┴─────────────┐      │   incoming:   │
    │  │           poll            │<─────┤  connections, │
    │  └─────────────┬─────────────┘      │   data, etc.  │
    │  ┌─────────────┴─────────────┐      └───────────────┘
    │  │           check           │
    │  └─────────────┬─────────────┘
    │  ┌─────────────┴─────────────┐
    └──┤      close callbacks      │
       └───────────────────────────┘
    
  • timer 阶段:执行到期的setTimeoutsetInterval回调队列(所以平时定时器执行的时间有时并不准确)
  • pending callback阶段:执行推迟到下一个循环迭代的I/O回调
  • idle, prepare阶段:仅内部使用
  • poll阶段(轮询):取出新的 I/O 事件;执行与 I/O 相关的回调(除了关闭回调,计时器调度的回调和 setImmediate 之外,几乎所有这些回调) 适当时,node 将在此处阻塞。
    如果轮询队列不为空,事件循环将循环访问队列并同步执行直到空。
    如果轮询队列是空的:
    1.如果脚本被 setImmediate 调度,则事件循环结束轮询,进入 check(检查)阶段执行那些被调度的脚本
    2.如果没有被 setImmediate 调度,则事件循环会等待回调被添加到队列中,然后立即执行
    在这个过程中,一旦轮询队列为空,事件循环还会检查已经到达时间阈值(或者超时)的计时器,如果有就回到定时器阶段执行对应的回调。
  • check阶段:执行setImmediate回调
  • close callbacks阶段:一些关闭的回调函数

setTimeOut( )与setImmdiate( )

执行时机不同

  • setImmediate 设计为在当前轮询 poll 阶段完成后执行脚本。
  • setTimeout 计划在以毫秒为单位的最小阈值过去之后运行脚本。

计时器的执行顺序将根据调用它们的上下文而有所不同

  • 如果两者都是主模块 (main module) 中调用的,则顺序将受到进程性能的限制(这可能会受到计算机上运行的其他应用程序的影响)。
  • 如果这两个调用在一个 I/O 回调中,那么 immediate 总是执行第一。

process.nextTick()与setImmediate()

  • process.nextTick 是在同一阶段立即触发,setImmediate是在事件循环接下来的阶段迭代中执行 - check 阶段。
  • process.nextTick () 比 setImmediate () 触发的更快。如果想设置立即异步执行一个任务,最好不要使用 setTimeout (fn,0),而是使用 process.nextTick () 或 setImmediate ()。

文章作者: John Doe
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 John Doe !
评论
  目录