NodeJS

概述

NodeJs是基于Chrome V8引擎的JS运行环境

作用:

可以让JavaScript能运行在服务端,并完成相应后端服务的一套API

  • 前后端分离解决跨域
  • 服务端渲染
  • 前端工程化服务与工具

合适场景:

I/O操作:文件网络和数据库等操作

不适用:

CPU密集型操作:高性能逻辑运算,解压缩,数据分析等操作

Node运行环境:

  • JavaScriptES部分
  • Node模块
  • Node API

核心思想:

是事件驱动,大量利用回调机制,如事件完成通知,异步的事件驱动

  1. function test(a, b, cb){
  2. const res = a + b;
  3. cb && cb(res);
  4. }
  5. test(1, 2, function(res){
  6. console.log(res + 3);
  7. });

非阻塞式I/O:

异步的输入和输出

外部依赖包与模块管理器npm

主线程交替处理任务

它是多线程同步模型的高并发能力(高性能处理线程池),多人访问服务器请求的场景

前后端分离解决跨域:

前端工程化服务与工具:

  • 开发代码:

    • .js/.jsx/.vue
    • .css/.scss/.less
    • .jpg/.png/.git
  • webpack node打包服务

    1. 文件读取
    2. 分析源码
    3. 编译源码
    4. 混淆压缩
    5. 打包文件
  • webpack node响应打包资源:

    • .js
    • .css
    • 压缩后的图片

单线程

JavaScript主线程是单线程,防止多个线程造成DOM操作与渲染任务冲突(GUI渲染与JS引擎线程运行互斥),Node中沿用了主线程为单线程的方式

多线程与单线程的优劣:

  • 多线程要频繁切换任务上下文处理多个问题
  • 单线程不需要不存在任务上下文切换问题
  • 多线程在处理多个问题时需要管锁机制
  • 单线程不需要管锁机制

多线程任务的运行规则:

例如三个线程同时切换做,在写入文件时有管锁机制

  • 线程1:看文档
  • 线程2:写代码
  • 线程3:回消息

单线程任务的运行规则:

事件都进入Node主线程运行,然后会有事件驱动通知回调函数进入任务队列,分配到线程池,线程完成时通知回调,执行回调函数

  • 事件1:看文档
  • 事件2:写代码
  • 事件3:回消息

同步异步

问题:什么是同步?

按照顺序往下执行,会存在堵塞的情况

问题:什么是异步?

和顺序无关和是否执行和是否得到结果无关的执行

事件环

通过事件环机制执行JavaScript代码,提供线程池处理I/O操作任务

两种线程:

  • 事件循环线程:负责任务安排(require,同步执行回调,注册新任务)
  • 线程池(libuv实现):负责处理任务(I/O操作,CPU密集型任务)

事件环阶段:

  • TimerssetTimeout,setInterval
  • Pending callbacks:执行延迟到下一个事件环迭代的I/O回调(内部机制使用)
  • Idle,prepare:系统内部机制使用
  • Poll:检查新的I/O事件与执行I/O回调
  • ChecksetImmediate
  • Close callbacks:关闭的回调函数(内部机制使用)

事件环阶段优先级:

Check > Timer > Poll

流程

Node事件环运行流程和案例分析

image-20220326011414092

image-20220326011513779

  1. //promise.then1
  2. Promise.resolve().then(() => {
  3. console.log(1);
  4. });
  5. //nextTick1
  6. process.nextTick(() => {
  7. console.log(2);
  8. });
  9. console.log('start');
  10. // I/O readFile1
  11. readFile('1.txt', 'utf-8', () => {
  12. //setTimeout2
  13. setTimeout(() => {
  14. console.log(3);
  15. });
  16. //nextTick2
  17. process.nextTick(() => {
  18. console.log(4);
  19. });
  20. //setImmediate2
  21. setImmediate(() => {
  22. console.log(5);
  23. });
  24. console.log(6);
  25. });
  26. console.log(7);
  27. //setTimeout1
  28. setTimeout(() => {
  29. console.log(8);
  30. });
  31. //setImmediate1
  32. setImmediate(() => {
  33. console.log(9);
  34. });
  35. console.log('end');
  36. //打印结果:
  37. 主执行栈
  38. 1. start (script)
  39. 2. 7 (script)
  40. 3. end (script)
  41. 4. 清空
  42. 6. 2 (nextTick1 cb)
  43. 8. 1 (promise.then1)
  44. 12. 9 (setImmediate1 cb) 或者 8 (setTimeout1 cb)
  45. 13. 8 (setTimeout1 cb) 或者 9 (setImmediate1 cb)
  46. 14. 清空
  47. 16. readFile1 cb
  48. 17. 6 (script)
  49. 19. 4 (nextTick2 cb)
  50. 22. 5 (setImmediate2 cb)
  51. 24. 3 (setTimeout2 cb)
  52. 微任务
  53. 5. nextTick1
  54. 7. promise.then1
  55. 9. 清空
  56. 18. nextTick2
  57. 20. 清空
  58. Node事件环阶段
  59. 10. setImmediate1setTimeout1
  60. 11. setImmediate1setTimeout1
  61. 15. readFile1
  62. 21. setImmediate2
  63. 23. setTimeout2

案例

案例:文档生成工具

A fast and light Document Creator 一个轻快的文档生成器

简介:

  • 这是一个基于vite的文档生成器插件
  1. 快速生成文件界面源码
  2. 编辑markdown生成html页面
  3. 快速生成文档菜单

技术:

  • vite
  • node

依赖:

  1. 依赖vite编译环境
  2. 插件内自动依赖markedhighlightjs

安装:

  1. 1.创建工程文件夹
  2. mkdir project-name
  3. 2.进入文件夹初始化npm
  4. npm init -y
  5. 3.安装vite 作者:尤雨溪
  6. npm i vite -D
  7. 4.修改package.json内部的scripts命令
  8. "scripts": {
  9. "dev": "vite",
  10. "build": "vite build"
  11. }
  12. 5.安装vite-doc-creator 作者:小野森森
  13. npm i vite-doc-creator -D

vite插件配置:

  1. 1.工程文件夹根目录下创建vite.config.js
  2. touch vite.config.js
  3. 2.vite.config.js配置插件
  4. const ViteDocCreator = require('vite-doc-creator');
  5. module.exports = {
  6. plugins: [new ViteDocCreator()]
  7. }

启动项目(生成文档编辑目录):

  1. npm run dev

插件配置项:

  1. //配置项位置
  2. module.exports = {
  3. plugins: [new ViteDocCreator({
  4. // 配置项
  5. })]
  6. }

配置项说明:

配置项 说明 默认值 必填
title 网页title与header文字标题 This is my first DOC by Vite-doc-creator
domain 生产环境下的域名(须带协议:http://或https://) http://localhost
port 生成环境下的端口号 process.env.npm_config_port

注意:为了避免页面链接生成错误,请尽量不要在开发环境下设置domainport,除非确保文档页面在该域名或该端口下可以正常访问。

使用方法:

  • workspace文件夹中创建.md文件进行编辑
  • 保存.md文件后,会自动将文件转换为html文件并生成文件菜单
  • 页面会自动展示,无需刷新页面

注意事项:

  1. 目前不支持在workspace内创建子文件夹(稍后更新会支持)
  2. 目前不支持修改workspace内的md文件名(稍后更新会支持)

原理:

  1. 创建文档工程目录 src -> js css html workspace
  2. 创建文件 复制:js/css/welcome.html 编译:index.html / md.html createIndexHtml mdToHtml
  3. 监听文件及文件夹变化 watchHtml / watchMarkdown 监听html文件夹 监听workspace文件夹

源码目录:

  1. ├─index.html - 组装字符串生成出来的项目根文件
  2. ├─package.json
  3. ├─vite.config.js - 用户使用时配置的文件/启用vite-doc-creator插件
  4. ├─workspace - 用户进行增删md文件的目录/增删会同步到src>html目录
  5. | koa&koa2&SSR.md
  6. ├─src - 用户开发时的源代码目录
  7. | ├─js
  8. | | index.js - 切换菜单的逻辑
  9. | ├─html
  10. | | ├─koa&koa2&SSR.html - 被同步新增的html文件
  11. | | welcome.html - 默认页面
  12. | ├─css - 页面样式文件
  13. | | ├─github-gist.min.css
  14. | | ├─github-markdown.min.css
  15. | | ├─index.css
  16. | | md.css
  17. ├─dev - 插件开发者的源代码目录
  18. | ├─vite-doc-creator
  19. | | ├─index.js - 插件出口文件/初始化
  20. | | ├─package-lock.json
  21. | | ├─package.json - 配置插件依赖
  22. | | ├─temp_files - 重要的文件/插件的初始文件
  23. | | | ├─js
  24. | | | | index.js
  25. | | | ├─html
  26. | | | | ├─index.html
  27. | | | | ├─md.html
  28. | | | | welcome.html
  29. | | | ├─css
  30. | | | | ├─github-gist.min.css
  31. | | | | ├─github-markdown.min.css
  32. | | | | ├─index.css
  33. | | | | md.css
  34. | | ├─libs - 工具函数集合
  35. | | | utils.js - 文件读取封装/创建菜单模板/组合baseUrl/替换html/创建iframe标签模板
  36. | | ├─init
  37. | | | ├─index.js
  38. | | | ├─initFiles.js - 复制初始jscss文件到src目录/首次生成根index.html/复制欢迎页
  39. | | | ├─initFolders.js - 创建/src目录和子目录
  40. | | | initWatchers.js - 监听/src和/workspace目录更新文件/页面加载和目录同步
  41. | | ├─config - 配置信息
  42. | | | index.js - 端口/域名/标题/内外部路径/正则规则
  43. | | ├─compiler - 解析的底层实现
  44. | | | ├─createHtml.js - 可复用的生成根index.html方法
  45. | | | ├─index.js
  46. | | | mdToHtml.js - 可复用的解析md文件为index文件的方法

源码地址: https://gitee.com/kevinleeeee/vite-doc-md-creator-demo