前端node理解并使用

/**
 * 什么是node.js
 *
 * 官方给出的定义是 谷歌的v8 js 运行环境
 *
 * 什么是 JavaScript 运行环境? --能够运行js的就是
 * 为什么 JavaScript 需要特别的运行环境呢? --任何高级语言都要
 * 什么是 JavaScript 引擎?--将js转为汇编语言,再转为机械语言
 *
 * stack Overflow 网站
 * https://stackoverflow.com/
 *
 * 可惜是个国外 英文网站
 *
 * 网速慢 翻译较难理解
 *
 * 该网站创始人之一 jeff Atwood
 * 任何可以用 js 来写的 应用程序 最终都会使用 js 来编写
 * (我不信这句话)
 *
 * js 发明之初 只是想 在浏览器里
 * 执行 简单的脚本 以及 操作dom
 * 其实 js 是非常局限的
 *
 * (果然这句话 在2007年是 只是一种美好的愿景
 * 在当时 这句话没有任何实现的可能性的)
 *
 * 但是 随着 node.js 的出现 这句话越来越真
 *
 * 为了能够理解 node.js 是如何做到的
 * 我们需要 了解 node.js的起源
 *
 * 因为 js 最早是运行在浏览器里面
 * 我们从浏览器作为切入口
 *
 * 一一去了解
 *
 * 浏览器的 控制台 可以直接编写js
 * 并在当前页面 生效
 *
 * 浏览器的内核承担 运行js代码 渲染图形 的功能
 * 内核  网景公司/火狐: Gecko
 *       微软         :trident/Blink(谷歌 edge opera)
 *       苹果/谷歌    :Webkit 开源
 *
 * 以上所有 内核 通俗上来讲
 * 被称为 排版(layout) 引擎
 *        浏览器(browser) 引擎
 *        样板引擎
 *        页面渲染引擎
 *
 * 引擎的工作过程
 *
 *
 * [HTML_Parser] 解析 .html
 * 生成 [DOM_Tree] dom树
 *
 * [CSS_Parser] 解析 .Style_Sheets
 * 生成 [Style_Rules] 样式规则
 *
 * 然后 使用 [Attachment] 进行附加
 * 最终生成一个 [Render_Tree] 渲染树
 *
 * 然后 与 [Layout_Tree] 布局树 (哪来的?)
 * 结合
 *
 * 在进行 绘制 [Painting]
 *
 * 一旦进行绘制 浏览器就能看到
 * 我们展示的页面了
 *
 * 前端应该会详细讲 这里不过多展开
 * 没有啊 前端我没学到这个啊
 *
 * 这过程中
 * 我们其实是
 * 可以在.html 中
 * 嵌入 <script> 标签的
 * 可以 操作 dom 等
 * 既然有 js
 * 就需要
 * 有东西 去执行 js 代码
 *
 * 被叫做 js引擎
 *
 * 高级语言->汇编语言->机器语言
 * js 属于高级语言
 * 需要逐步转换成 机器语言 才能被计算机认识
 *
 * js引擎 完成了 转换至机器语言的工作
 *
 *.html 中有 js 时
 * 渲染引擎会暂停
 * 优先让 js引擎去解析 js
 *
 * 这样渲染出的 dom 有被js操作过
 * 逐步 是为了 不用频繁的 更新 dom 树
 * 懂了
 *
 * 但是鲜有人 把 js 写在 .html的中间吧
 * 要么是开头 要么是 结尾
 * 不过 php 到是常写在中间
 *
 * 我去
 * 前面的内核 是内核 不是 js引擎
 * 内核 是浏览器 内核(引擎)
 * js引擎是 js引擎
 *
 * 是两个东西
 * 常见的js 引擎有
 *   SpiderMonkey      : 初号机 有js作者开发
 *   Chakra            : 微软开发 用于ie浏览器
 *   javascriptcore    :Webkit中内置的js引擎(我去 内核还能自带js引擎) 苹果开发
 *   V8                : Google开发的强大 js引擎,非常好用
 *
 * 浏览器 内核 与 js引擎 的关系
 * 拿 Webkit 举例
 * Webkit 是由两部分东西组成的
 *  1.WebCore:  浏览器内核 解析.html 布局 渲染
 *  2.JavaScriptCore: js引擎 解析 js
 *  解析js 时 暂停 解析 .html
 *
 * 所以 浏览器内核 一般是由 两部分组成
 *        js 引擎 和 Html&&Css引擎
 *        逻辑层      渲染层
 *
 *
 * 在小程序中 是使用 JSCore 来 解析的 js
 *             使用  webview 解析 .html&&.css
 *
 *
 * 接下来
 * 我们主要了解 最牛逼的 V8 js引擎
 *
 * V8 :
 *     c++编写的
 *     开源的
 *     解析 js的
 *     解析 WebAssembly的(目前用的较少)
 *
 *     装载在 Chrome 上
 *     装载在 Node.js 上
 *
 *     运行在 win7或更高
 *            macOS 10.12+
 *            linux x64/IA-32/ARM/MIPS(cpu架构)
 *
 *      V8 既可以独立运行 也可以嵌入到任何 C++ 应用程序中
 *
 *      C++ 应用程序指 电脑浏览器 或 node.js
 *
 * V8 指的是 名字 而不是 版本为 8
 *
 * V8发动机,是内燃机的汽缸排列型式之一。
 * 一般使用在中高端车辆上。
 * V8表示的是发动机汽缸的排列形式和缸数
 *
 *
 * V8 的执行 过程
 *
 *
 * V8引擎本身的源码非常复杂,大概有超过
 * 100w 行C++代码,但是我们可以简单裂解一下
 * 它执行 JavaScript代码的原理
 *
 *早期 windows 98 大概也只有 500w 行
 * 现在肯定不止
 *--------------------------------
 * 首先 通过 V8的内置模块 [Parse] 解析 .js
 * 通过 js语法规则 生成 [AST抽象语法树]
 *
 * 再由 V8的内置模块 [lgnition]解释器 解析后
 * 输出 近似汇编语言[bytecode] 字节码 代码
 *
 * 或 再由 V8的内置模块[TurboFan]编译器 解析
 * 输出  机器语言[MachineCode]
 *-------------------------------------
 * 编译器 编译的编译 语言 编译时相对简单效率高 好像只编译一次
 * 解释器 解释的解释 语言 解释时相对复杂效率低 好像每次都要解释
 *
 * js 也是像php 一样两种都可以
 *
 * 突然更换 函数形参的类型会 影响 V8 引擎的性能
 *
 * 所以 ts 的类型限制 提高了性能
 * js 还能转成 ts? 可以
 *
 * 所以 ts 编译而成的 js 某种程度上来说也是可以提高性能的
 *
 * V8 官网(V8工作原理)
 * https://v8.dev/
 *
 *
 * node.js 不止有V8
 *
 * Chrome浏览器:
 *               HTML/CSS 代码
 *               JS 代码
 *               Bink 视图渲染
 *               V8   js逻辑
 *               中间层 对系统做一些操作 比如 打印
 *               操作系统(网卡,硬盘,显卡)
 * Node.js(仅有):
 *               JS 代码
 *               V8   js逻辑
 *               中间层(lib uv) 对系统做一些操作 比如 打印
 *               操作系统(网卡,硬盘,显卡)
 *
 * lib uv 非常重要 后面会详细讲
 * lib C语言编写的库
 * uv 独角伶盗龙 指速度非常快
 *
 * 所以 node.js 中里面不同 模块
 *  是使用不同语言来编写的
 * 包含以下语言
 * js       54.6%
 * C++      28.6%
 * Python   12.1%
 * C         2.6%
 * HTML      0.9%
 * Makefile  0.3%
 * Other     0.9%
 *
 * node安装时 会 配置环境变量       v 10.15.3
 * 还会默认安装 npm                 v 6.4.1
 *
 * node 的版本在非window 可以管理
 *
 *  nvm : 在多个node.js 版本之间来回切换
 *  n : 作者tj github
 *      npm i n -g  //安装n
 *      n -v        //查看版本
 *      sudo n lts       //安装 node的lts 稳定版版本
 *      //sudo mac 电脑上的最高权限
 *      --------------
 *        sudo n latest      //安装 node的 latest 开发板版本
 *
 *       安装后 node -v 就是 n 装的版本
 *       如果敲 sudo n  就是 有通过 n 安装的版本可供选择
 *       上下选择哪个哪个就是 默认node 版本
 *       mac 电脑不分盘
 *
 *
 * nvm-windows : 支持windows
 *              github 搜索官方 nvm
 *              会提示 不支持 windows
 *              但是会 建议使用 nvm-windows 或 nodist
 *              我们直接点击  nvm-windows 连接跳转
 *
 *              就到了 nvm-windows 的github
 *
 *              有node 时
 *              安装 nvm-windows 后会提示要不要加入管理
 *
 *
 *              没有node时
 *              点击 Download the latest installer from the releases
 *              下载 nvm-setup.zip 会自动配置环境变量
 *              解压后 为.exe
 *
 *               安装后
 *               重新打开 黑窗口
 *               输入 nvm 回车
 *               可以看到 一大堆 nvm 的信息
 *
 *               nvm list 查看已安装的 所有node 版本
 *
 *               设置 nvm 的国内淘宝镜像
 *               nvm node_mirror https://npm.taobao.org/mirror/node/ 回车
 *
 *               设置 npm 的国内淘宝镜像
 *               nvm node_mirror https://npm.taobao.org/mirror/npm/ 回车
 *
 *               nvm list available 查看可下载的 所有node 版本
 *               nvm install 14.13.1 指定版本
 *               nvm install latest 指定最新开发版本(可能会提示不是有效的版本)
 *               nvm install lts 指定最新稳定版本(可能会提示不是有效的版本)
 *
 *               安装好 之后
 *               nvm list 查看已安装的 所有node 版本号
 *               nvm use 14.13.1 选择使用该安装的node版本
 *               会提示 now using node v14.13.1 (64-bit)
 *
 *               此时 node --version 就是 选择的版本号了
 *
 *              卸载某个 已安装的版本
 *              nvm uninstall v14.13.1 回车
 *
 *              win7最高支持 13.14.0 版本
 */
// console.log("Hello World");
// function sum(num1, num2) {
//     return num1 + num2;
// }

// console.log(sum(20, 30), (new Date()).valueOf());
// console.log(sum(20, 30), (new Date()).valueOf());
// console.log(sum(20, 30), (new Date()).valueOf());
// console.log(function () { console.log(1) }, sum(1, 'bbb'), (new Date()).valueOf());

// setTimeout(() => {
//     console.log('定时器被执行', (new Date()).valueOf());
// }, 1000);
/**
 * node 的 repl(控制台)
 * 读取-求值-输出 循环
 * 简单的编程交互环境 就是 终端界面 中
 *
 * 使用node 回车 进入/ 浏览器不用直接有
 * 一种可输入 .js命令 执行(交互) 的环境
 * 连续两次 ctrl + c 退出
 *
 * 多行代码时 按照格式化 规则
 *  输入一行 回车一下
 * 会出现 ... 可继续输入
 *
 *
 *
 * 今日 2021 7 10
 * node 参数传递(字符串):
 *              在终端中传递
 *              ctrl+` 在当前路径打开终端
 *              输入 node 前言.js coderwhy age=18 回车
 *
 *              在程代码中获取
 *              console.log(process)//内置全局变量 process
 *              console.log(process.argv[0])//node.js 的地址
 *              console.log(process.argv[1])//当前文件的 地址
 *              console.log(process.argv[2])// 'coderwhy'
 *              console.log(process.argv[3])// 'age=18'
 *              argv 是个数组
 *
 */
//  console.log(process)//内置全局变量 process
// console.log(process.argv[0])//node.js 的地址
// console.log(process.argv[1])//当前文件的 地址
// console.log(process.argv[2])// 'coderwhy'
// console.log(process.argv[3])// 'age=18'
// console.clear() //清空控制台
// console.trace() //打印函数的 调用链

// console 也是全局变量 

//常见的全局变量有哪些

/**
 * 1.console 全局变量
 * 2.module  全局变量
 * 3.expprts 全局变量
 * 4.require() 全局方法  require全局变量
 *
 *
 *  特殊的 全局变量(各模块(.js)中的npc)
 *  __dirname 当前目录变量
 *  __filename (当前目录 + 当前文件名)变量
 *  exports
 *  module 全局变量
 *  require()
 *
 *
 * 关于 定时器
 * 1. settimeout 延时器 全局方法
 * 2.setinterval 定时器 全局方法
 * 3.setImmediate 立刻 延时到最后执行 全局方法
 * 4.process.nextTick 下一个 dom渲染时 全局方法
 */
// setImmediate(() => {
//     console.log(1000)
// });

// process.nextTick(() => {
//     console.log('process.nextTick')
// })

/**
 * 关于 真 全局 总变量
 * global  相当于浏览器的 window
 *
 */

// global.a = 1
// console.log(global.a)


/**
 * js的模块化(与 src 引入不同的是 模块化中 变量名互不影响)
 *
 * 早期 js 存在没有模块化的缺陷
 *
 *  模块化 类似于封装vue组件的方式
 *
 *  话说vue的组件 就是 一种模块化吧(不过使用又很大区别)
 *  怪不得
 *  原来 是 vue 的模块化 是一种
 *              直接 import .vue地址 使用 注册及使用组件标签
 *         .js 的模块化 又是一种
 *               export 导出 函数方法
 *               另一处 import {函数方法名 } from (export时的路径)
 *
 *   是两种
 *
 *   lisp 语言 古代人工智能语言 类似 js
 *
 *   js 有很多模块化规范
 *   1.AMD(较少,基本不用)
 *      去 github下载  require.js 到本地
 *        在 index.html中
 *             <script src='./require.js' data-main="./index.js"></script>
 *                index.js 模块化的入口启动文件
 *
 *        在 index.js中 拿到require.js定义的 require全局变量
 *             (function(){
 *                 require.config({
 *                       baseUrl:'',
 *                       paths:{
 *                        "bar":"./bar",//不能加 .js
 *                        "foo":"./foo",
 *                        }
 *                   })
 *             })();
 *       用到了再说吧...太多了记不住
 *
 *   2.CMD(较少,基本不用)
 *       去gethub 下载 sea.js
 *       用到了再说吧...太多了记不住
 *
 *   3.CommonJS(主要)
 *     ...
 *
 * 普通方式: IIFE 立即匿名函数调用表达式
 * (不建议) 普通 .html 引入  script 标签 src
 * 在自己的 多个 脚本中
 * 定义想要 在其之间传递的参数
 * 在  将所有需要传递的参数
 * (使用或不使用 IIFE 都可)
 * 赋值给 一个 全局 变量(相对于 .html src中引入的 所有 js 来说)
 * 该变量在 同.html中 其它 script src 中 可用
 * 变量名比较 长 唯一  就可以了
 *
 * 主流方式:CommonJS(用路径 代替了 普通方式可能重名的 全局变量问题)
 *  ① CommonJS 简称 CJS 起初(称为ServerJS)应用在服务器上(node)
 *       在 node 中:
 *           每一个js文件都是一个单独的模块
 *           单独的模块化 意味着 有自己的作用域
 *           导出作用域方法
 *                          简写(中间商)
 *                          exports {} 全局变量 npc
 *                          相当于 exports={}
 *
 *                          全写(厂家)
 *                          module.exports 全局变量 npc
 *                          module 指 每一个 .js (模块)
 *                          都存在的类new出来的实例
 *                          真正办事的 是厂家module.exports
 *
 *                          厂家 module.exports.name 修改时所有同步
 *                          但是
 *                          厂家 module.exports={} 新对象时
 *
 *                          中间商 exports 将被遗弃在某个空间 不被使用
 *
 *                          module.exports=exports 将出现断层
 *                           ( 此行在.js 最先执行 且默认 exports={}
 *                             因此 .js 中 exports=非指针 均不生效
 *                            也意味值 exports 无法导出单纯的 数字 或字符串)
 *
 *
 *           导入作用域方法
 *                        const bar =  require('./bar') 全局方法 npc
 *                        return 该.js路径 一个导出exports的对象
 *                        当前 .js的require()         npc
 *                        会获取到 bar.js的 exports   npc
 *                        并赋值给当前 .js 中的变量bar
 *
 *                        常见 require(?) 查找规则
 *                        1.?是 ./或../或/(根目录) 开头
 *                          查找本地 ?文件 或
 *                          ?下一级目录的 index.?
 *                        2.?是核心模块 path或http
 *                          返回核心模块
 *                        3.直接写 ?(没有路径)
 *                          且不是核心模块
 *                          在编写代码的 当前路径中
 *                          逐层 一级一级向上
 *                          搜寻 node_modules
 *                          然后查找 ?
 *
 *
 *  ② 随后运行在 浏览器上 Browserify
 *  ③ webpack 模块化打包工具具备对 CommonJS的支持和转换
 *
 *   2021 7 12
 *
 * 模块的加载过程
 * 模块第一次 被引入 require() 读取时
 * 其内部 .js中的代码 会运行一次 并缓存
 * 标志为 其 Module.loaded 由false 变为true
 *
 *  当很多 .js模块相互 require()加载时
 *  node.js 会采用最优算法 进行缓存
 *  避免重复加载
 *  算法: 沿着一条路加载到底 (图结构 : 类似蜘蛛网) 其它 树结构,数组,哈希表,链表
 *        然后返回一级 判断是否有分叉 该分叉是否被缓存过
 *        无分叉 或 被缓存过 返回上一级
 *        有分叉 且 没被缓存过  沿着这条路加载到底
 *
 *  图的遍历一般有两种算法
 *          上面使用的是深度优先
 *          还有一种的广度优先 : 按节点一层一层
 *                   遍历完第一层 遍历第二层 ...
 *
 *
 * node源码解析
 *  太复杂听不懂
 *
 * CommonJS 缺陷
 * 1.同步: 只有等到对应的模块加载完毕,当前模块中的内容才能被运行
 *    在服务器时 是本地.js 非常快
 *    问题在于浏览器
 *
 * 2. 浏览器中 会首先先将 .js 文件从服务器下载下来
 *    才能加载运行后面的代码
 *
 * 3.因此 我们在浏览器里是不使用 CommonJS 规范 加载 http的
 *   webpack 的CommonJS 是另一回事
 *   webpack 会将我们的代码直接转成浏览器可执行的代码
 *
 *
 *
 *
 * -----------------------------------------------------
 *  一. 认识 ES Module js模块化
 *  之前的 3种模块化都是社区规范
 *  是因为 js 没有自己的模块化
 *  所以 才用它们
 *  现在(es6 2015) 有了 是不是可以不用了?
 *
 *  ESModule(采用关键字 标记的形式 被解析时才会生效 并非一个对象或变量)
 *
 * 在 html中使用(浏览器的 js引擎)
 * <script src="./index.js" type='module'> <\script>
 * 现在 index.js 哪怕是空的 也会当做模块文件来使用
 * 使用 type='module 时 需要开启服务 否则会跨域错误
 * 使用 live server 打开即可
 *
 * 现在index.js就已经是一个模块了
 *
 * ①export 导出    区别于 exports/module.exports
 *     主要有三种:1. 分别导出
 *                      export let name='函数或对象';
 *                     //导出的 是 name
 *                2. 统一导出 定义过的 变量引用列表 , 号隔开
 *                     export {
 *                         name,其它变量,对象,函数
 *                      }
 *                    {} 不是对象是固定被解析的一种语法
 *                3. 导出时 起别名
 *                      export {
 *                         name as 别名,
 *                          其它变量,
 *                          对象 as 别名,
 *                          函数
 *                      }
 *                    {} 不是对象是固定被解析的一种语法
 *
 *
 * ②import 导入    区别于 require('')
 *          同样有三种:1. 统一导入
 *             import { 别名,
 *                      其它变量,
 *                      别名,
 *                      函数  } from './xxx.js' //.js不能省略(webpack 可省略)
 *
 *                   2. 统一导入+起别名
 *             import { 别名 as 别名(可以再起),
 *                      其它变量,
 *                      别名 as 别名(可以再起),
 *                      函数  } from './xxx.js' //.js不能省略(webpack 可省略)
 *
 *                  3. 统一导入+起别名
 *             import  * as 别名(总变量)
 *                     from './xxx.js' //.js不能省略(webpack 可省略)
 *
 * 补充:
 *   结合使用
 *         1.默认 中转 导出全部 的简写
 *                       export {变量 as 别名,函数,对象 } from '.xxx.js'
 *
 *            目的是 :为了创建一个中转.js
 *                   统一管理自己所有 其它.js
 *                   封装的 暴露 接口方法
 *
 *
 *          2.default export(唯一)
 *            之前 export 都是named 名字导出
 *           其缺陷在于 当我不知道 导出时的名字时
 *
 *           我是无法 import 导入的
 *
 *           因此出现了
 *           default export function(){} 默认导出
 *           // 且可与 CommonJS 配合(后面讲)
 *
 *           import 任意名字 from './xxx.js'
 *           任意 名字就是函数 function(){}
 *
 *          3. import 是不能出现在 代码逻辑中的
 *             if(true){
 *                  import xx from './xxx.js'
 *
 *             }
 *             这写法是会报语法错误的
 *             xxx.js 是被 js引擎 parsing 先分析
 *                                生成Ast树
 *                                再转成字节码bytecode
 *                                运行
 *
 *             代码逻辑中 说明已经处于  运行 阶段
 *             无法进行  分析 import xx from './xxx.js'
 *             就会报错
 *
 *             但是 const a=require('./xxx.js') 可以
 *             因为 require() 是个全局函数 npc
 *             是 代码 可直接运行
 *             而 import from 是关键字语法
 *             需要 先 分析
 *
 *             所以 要分析的关键字 和 可直接运行的函数
 *             不能直接写在一起
 *
 *             webpack 既有 esmodules CommonJS
 *
 *             纯 esmodules 模块化 环境下 解决办法
 *             //解决办法:
 *                  import('./xxx.js').then(res=>{ // 成功回调
 *                  //此时是异步函数, 且返回一个 posmisze
 *
 *                   console.log(res.xxx.js导出的东西1)
 *                   console.log(res.xxx.js导出的东西2)
 *                   console.log(res.xxx.js导出的东西3)
 *
 *                     }) .catch(err =>{// 失败回调
 *
 *                    })
 *
 *              大部分脚手架->都是基于 webpack
 *              所以 import('./xxx.js')
 *               本质上是被 webpack 解析的
 *                单独打包 按需加载
 *
 *                     CommonJS 模块是同步的   会阻塞后面的代码
 *                     esmodules 模块是异步的 不会阻塞后面的代码
 *               也就是说 即使不是 esmodules 模块
 *               也可以加 type='module' 将普通的.js 变成
 *                异步加载(本来是同步的)
 *
 *
 * esmodules 的加载过程
 *   export{函数,变量,对象 }
 *        函数,变量,对象
 *        与 本源 函数,变量,对象
 *        是 变量 赋值的关系 的
 *
 *       在另一处 模块环境记录空间中
 *          引用原.js 的函数,变量,对象
 *              进行 赋值
 *          并不断 watch 重新赋予最新的值
 *        const 函数=函数
 *        const 变量=变量
 *        const 对象=对象
 *
 * const 之后()(赋值是 字符串时)
 * 在import 的.js中 是不能重新定义的
 *
 * const 之后()(赋值是 对象的 内存地址时)
 * 在import 的.js中 是能重新定义 对象. 中的内容的
 *
 *
 *
 *
 *
 *
 * 2021 7 13
 * // 纯 node.js (不含html,不含webpack,不含脚手架) 常见的内置模块解析
 *     默认 .js 只是 CommonJS 的模块
 *     而不是 Es6 的模块
 *
 *           在pack.json中可以 设置 'type':'module'
 *           或
 *           使用 .mjs 后缀
 *
 *     来使一个 .mjs 文件成为 Es6的模块
 *
 *     注意所有 from './xxx.mjs' 也要使用 .mjs 后缀
 *
 *     低版本 node.js 可能不支持 原生Es6 的模块
 *
 *     可能需要加 node index.mjs --experimental-modules
 *     才能运行
 *
 *
 *
 *
 *  Esmodules 和 CommonJS 交互
 *
 * export {变量,函数,对象}  -- import {} from './xxx.js'
 * //正常示例
 *
 * export {变量,函数,对象}  -?- const a =require(./xxx.js)
 * //正常情况 require 是无法 加载 export 导出的变量的
 *         CommonJS的           Esmodules的
 *
 * node.js 不支持
 * 某些平台 可以针对性 解析 有可能会支持
 *
 * 但是
 * exports {变量,函数,对象}  --- import {变量,函数,对象} from(./xxx.js)
 * //正常情况 import 是可以 加载 exports 导出的变量的
 *          Esmodules 的         CommonJS 的
 *  exports {}  //CommonJS的
 * 会转换成
 * default export function(){}//Esmodules的
 *                            //默认导出无名的东西
 *
 * 我的 node v10.15.3 并不支持这 混合使用功能
 *
 *
 *
 *
 * Esmodules 和 CommonJS 模块化所有内容到此结束
 *
 *
 * 2021 7 14
 *  node.js 的 内置模块 path 模块
 *
 * 其用途在于 对 系统文件路径 和 操作文件
 * 封装 并提供了一些 必备的 函数方法
 *
 *   关于系统文件路径
 *              windows     支持 \, \\ ,/
 *              Mac/linux 只支持       /
 *
 *  不过不用在意
 *  node.js 能帮我们决定
 *  何时该使用
 *  哪种文件路径分隔符
 *
 *  我们使用 CommonJS模块化 读取
 *  node.js 内置导出的 path 模块
 *
 *
 *
 *
 *
 */
// const a = require('path')//拿到内置模块 
// import a from 'path' 也可以 node.js两种模块化都支持(.mjs)
// const basePath = 'D:/C/前端/node.js_codewhy/node_js_codewhy'
//定义 文件默认主目录 支持传入所有已知 文件分割符号(\, \\ ,/)
// const fileName = '前言.js'
//定义 文件路径 
//1.
// const filepath = a.resolve(basePath, fileName)
//使用 path内置模块 的方法
//                            文件路径    文件名

//filepath 在不同操作系统上会有不同表现

// console.log(filepath);
// 我的windows上是
// D:\C\前端\node.js_codewhy\node_js_codewhy\前言.js

//同样代码
//老师Mac 上是
// User/前端/node.js_codewhy/node_js_codewhy/前言.js

//Mac 只有一个盘 不分盘的


//2. 使用node.js的内置path模块 
// 从 一个绝对路径字符串中 获取字符串内容 所指目录   dirname
//                                           文件名 basename
//                                           后缀名 extname
// const filepath = 'D:/C/前端/node.js_codewhy/node_js_codewhy/前言.js'

// console.log(a.dirname(filepath));
//D:/C/前端/node.js_codewhy/node_js_codewhy

// console.log(a.basename(filepath));
//前言.js

// console.log(a.extname(filepath));
//.js

// 3.使用node.js的内置path模块 
// 
// const basepath = 'D:/C/前端/node.js_codewhy/node_js_codewhy'
// const fileName = '前言.js'

// const filepath = a.join(basepath, fileName)
// // 同样是路径拼接 那么 他与 a.resolve 路径拼接有何不同呢
// const filepath2 = a.resolve(basepath, fileName)
// // 区别:
// //      resolve 能判断 ./  ../  / 开头的路径 更好用
// //                     没有时 为当前执行代码文件的默认目录
// //      join    不能  不好用 纯字符 拼接

// console.log(filepath);
// //D:\C\前端\node.js_codewhy\node_js_codewhy\前言.js
// console.log(filepath2);
// //D:\C\前端\node.js_codewhy\node_js_codewhy\前言.js

// webpack 中的应用
// const resolve = (dir) => { return a.resolve(__dirname, dir) }
// console.log(resolve('111'));
// D:\C\前端\node.js_codewhy\node_js_codewhy\111

// node.js的 path 内置路径模块 到此结束

/**
 *  接下来讲关于文件系统(fs) 的操作
 *
 * fs: 全称 File System 指 node.js的文件系统 内置模块
 *
 *  服务器/或服务器框架 几乎都有文件系统
 *
 *  主要作用
 *  1.将 各类型文件放到不同地方
 *  2.其中包含 连接数据库  将不同类型数据存入数据库等
 *  3.其它特殊 的配置文件 或 用户资源(图,音.字,视频) 等都是文件
 *
 *  功能
 *   我们主要 借助于 fs文件系统中的内置node.js模块
 *    封装的方法 可以在不同的系统中
 *    使用同种 方法操作我们的文件
 *
 *    这是 使node.js 可以成为(开发) 后台服务器 的主要原因
 *
 *   当时学习 php时 文件操作 api 非常多
 *   node.js也是如此
 *
 *    因此我们不肯也没必要一个一个的去学习
 *   更多的应该是作为 api 查询手册 等用到的时候查询即可
 *
 *    学习阶段我们只学常用的即可
 *
 *    每个 api 几乎都有 3种 操作方式
 *    1. 同步操作文件:代码会被阻塞
 *    2. 异步回调函数操作文件:代码不会被阻塞,需要传入回调函数
 *                           当获取到结果时,回调函数执行
 *
 *    3. 异步 Promise 操作文件:代码不会被阻塞,通过 fs.promises
 *                           调用方法操作,会返回一个 promises,
 *                           可以通过then , catch 进行处理;
 *
 *
 *
 *
 */
// const a = require('fs')

//接下来 读取文件的属性(非内容)
// 1.同步
// const info = a.statSync(__filename)
// //获取当前文件的 属性
// console.log(info);

// 2.异步 回调函数  
// a.stat(__filename, (err, info) => {
//     if (err) console.log(err);
//     else if (info) console.log(info);
// })
// console.log(111);//111 可能在异步之前打印

//  3.Promise(小部分api并不支持 注意看版本)
// a.promises.stat(__filename).then((info) => {
//     if (info) console.log(info);
// }).catch(err => {
//     if (err) console.log(err);
// })
// console.log(111);//111 同样可能在异步之前打印
//优点是不会陷入 回调地狱
//node.js内置文件系统(fs)的  
//通用的
//3种api类型操作方法 举例完毕

/**
 *  文件描述符
 *       通常指各系统用于追踪当前打开文件的 标记
 *
 *  而在node.js中
 *
 *  文件描述符
 *       指 适用于 各系统 用于追踪当前打开文件的 统一标记
 *        该标记 由node.js制造 并识别
 *
 *
 */
//  flags 是指
// ‘r’ - 以读取模式打开文件。如果文件不存在则发生异常。
// ‘r+’ - 以读写模式打开文件。如果文件不存在则发生异常。
// ‘rs+’ - 以同步读写模式打开文件。命令操作系统绕过本地文件系统缓存。
// ‘w’ - 以写入模式打开文件。文件会被创建(如果文件不存在)或截断(如果文件存在)。
// ‘wx’ - 类似 ‘w’,但如果 path 存在,则失败。
// ‘w+’ - 以读写模式打开文件。文件会被创建(如果文件不存在)或截断(如果文件存在)。
// ‘wx+’ - 类似 ‘w+’,但如果 path 存在,则失败。
// ‘a’ - 以追加模式打开文件。如果文件不存在,则会被创建。
// ‘ax’ - 类似于 ‘a’,但如果 path 存在,则失败。
// ‘a+’ - 以读取和追加模式打开文件。如果文件不存在,则会被创建。
// ‘ax+’ - 类似于 ‘a+’,但如果 path 存在,则失败。

// const a = require('fs')
// a.open(__filename, 'r', (err, fd) => {
//     if (err) console.log(err);
//     if (fd) console.log(fd);//3

//     //然后可以使用 许多函数 通过 3 找到该文件 进行操作
//     a.fstat(fd, (err, info) => {
//         if (err) console.log(err);
//         if (info) console.log(info);
//         //通过标识(fd) 3 找到该文件的属性(info)
//     })
// })


/**
 * 关于文件的读写
 * 还是 node.js的内置文件系统(fs)模块
 *
 *
 */
//写
// const a = require('fs')
// a.writeFile('./index2.mjs', '\nhhj', { flag: 'a', encoding: 'utf-8' }, (err) => {
//     //覆盖写 (默认) { flag: 'w' }
//     //追加写        { flag: 'a' }
//     //  \n 换行
//     //  encoding: 'utf-8' 默认 写读必须统一编码 否则乱码
//     if (err) console.log(err);
// })

//读
// const a = require('fs')
// a.readFile('./index2.mjs', { flag: 'r', encoding: 'utf-8' }, (err, data) => {
//     //读 { flag: 'r' } 不写默认
//     //
//     // 
//     //  encoding: 'utf-8' 默认 写读必须统一编码 否则乱码
//     //没有指定编码是 返回一个 二进制的 另一种表现形式Buffer
//     //<Buffer 0a 68 68 6a 0a 68 68 6a 0a 68 68 6a 0a 68 68 6a 0a 68 68 6a 0a 68 68 6a>
//     if (err) console.log(err);
//     if (data) console.log(data);
// })

/**
 * 还是 讲 node.js的内置文件系统(fs)模块
 * 文件夹的操作
 *
 *
 */
//    1.创建文件夹
// const a = require('fs')
// const dirname = './why'
// if (!a.existsSync(dirname)) {
//     //如果(同步判断)文件夹不存在
//     a.mkdir(dirname, err => {//则创建它
//         if (err) console.log(err);//如果创建失败 打印err
//     })
// }



//    2.读取文件夹中的所有文件
// const a = require('fs')
// const dirname = './why'
// a.readdir(dirname, (err, files) => {
//     if (err) console.log(err);//读取失败返回
//     if (files) console.log(files);//读取成功返回 文件列表
//     // [ 'index.mjs', 'index1.mjs', 'why copy', '前言.js' ]
// })


//  2.1 拓展 递归深入逐层遍历文件夹内 每一个文件夹
// const a = require('fs')
// function getFiles(dirname) {
//     a.readdir(dirname, { withFileTypes: true }, (err, files) => {
//         if (err) console.log(err);//读取失败返回
//         if (files) {
//             console.log(files);//读取成功返回 文件列表
//             // [ 'index.mjs', 'index1.mjs', 'why copy', '前言.js' ]
//             for (let value of files) {
//                 //仅仅通过 数组中的 名称 无法精确判断
//                 //一个东西是文件 还是文件夹 
//                 //通过完整路径 使用 .stat 才足以判断  可是有点麻烦

//                 //isFile()//判断是否是文件夹 
//                 //isDirectory()//判断是否是文件夹

//                 //{ withFileTypes: true } 原来 自带识别文件类型的功能 没开启而已

//                 // [ Dirent { name: 'index.mjs', [Symbol(type)]: 1 },
//                 // Dirent { name: 'index1.mjs', [Symbol(type)]: 1 },
//                 // Dirent { name: 'index2.mjs', [Symbol(type)]: 1 },
//                 // Dirent { name: 'why copy', [Symbol(type)]: 2 },
//                 // Dirent { name: '前言.js', [Symbol(type)]: 1 } ]
//                 //返回的是 呃 这什么形式

//                 // 现在可以使用  .isDirectory() 判断是不是文件夹了
//                 if (value.isDirectory()) {
//                     //如果是文件夹
//                     const path = require('path')
//                     const filepath = path.resolve(dirname, value.name)
//                     //               智能拼接
//                     //拼接出 路径+名字后 
//                     //可以进行下一步了

//                     //再次打开这个文件夹
//                     getFiles(filepath)

//                 } else {//否则打印出不是文件夹的名字
//                     console.log(value.name);
//                 }

//             }
//         }

//     })
// }
// getFiles('./why')

//promise.all 异步读取多个文件后一起返回

//    3.文件夹的重命名(极少使用)
// const fs = require('fs')
// fs.rename('./why', './why2', err => {
//     console.log(err);
// })
//奇怪 此处重命名 index.mjs  成功
//重命名 why 文件夹却 报错

//这些关于文件夹的操作就已经讲完了


//作业: 封装一个 将文件夹 复制到 另一处的 ji工具 

//  运用知识: node.js的内置模块文件系统(fs) 操作
//             node.js的内置模块 路径(path) 处理

// 效果: 传入两个路径  将路径中文件 复制到 另一个路径内

//可能用到的知识  
// console.log('1'.padStart(2, 0));//01
//resolve 路径拼接 

//也因此 node.js 是可以做很多 自动化的小工具的




/**
 * 2021 7 15
 * 接下来 我们来看 node.js内置的核心模块(events)
 *
 *  声明:   node.js 的所有 核心模块
 *          都是基于异步事件驱动的(异步循环这些东西后面还会给大家讲到的)
 *
 * 工作过程: 在某个运作体系中
 *           可能存在对象(此处特指发射器(Emitters))
 *           发出某一个事件
 *
 *           然后,我们(程序员)可以写(监听器 Listeners)
 *           监听这个事件
 *           并写入 触发监听事件时 的回调函数
 *
 *           总的来说
 *           此函数 将随即被 监听到的发射器 调用
 *
 *           并类似于 事件总线 或 子向父发送事件
 *
 *           难道 events 就是 vue 的事件总线? 是的
 *
 *            实现此过程的方法较多
 *            接下来进行部分演练
 *
 *
 */
// const EcentEmitter = require('events');

// //实例化 类对象 (特指 发射器Emitters)
// const emitter = new EcentEmitter();

// //监听 某一个发射的事件
// // addListener: 监听
// // on:       addListener 的 别名 或 简写
// emitter.on('click', (...e) => {
//     console.log(e, 1);
//     //[ '99', 33, 22, 11 ] 1
// })


// let hh = (...e) => {
//     console.log(e, 2);
//     //[ '99', 33, 22, 11 ] 2
// }
// emitter.on('click1', hh)


// // 发出一个事件
// emitter.emit('click1', '99', 33, 22, 11);//开启监听 传入参数
// //会触发所有 监听 1 和 2
// emitter.off('click1', hh);//取消监听 传入函数
// //会 关闭 2 的监听
// emitter.emit('click1', '99', 33, 22, 11);//开启监听 传入参数
//只会打印 1

// 所以最终结果是 1 2 1 少了一个2
//被 emitter.off('click1', hh);//取消监听 传入函数
//提前关闭了

//因此 可以理解为 我可以提前关闭 某些不想被触发而连动的监听


/**
 * 下面还有一些
 * 不是很常用的方法(了解)
 *
 *  node.js 核心模块(events)获取 信息 (指绑定注册的事件)
 *
 *
 */
// const EcentEmitter = require('events');//使用 node.js 核心模块(events)
// const emitter = new EcentEmitter();//创建发射器

// let hh = function () {
//     console.log(arguments, 2);
//     //[ '99', 33, 22, 11 ] 2
// }
// emitter.on('click1', hh)// 监听发射器  必须先监听
// emitter.on('click1', hh)// 监听发射器  必须先监听
// emitter.once('click2', hh)// 监听发射器  必须先监听
// //once 即使发射两次 也只接受一次信息
// emitter.prependListener('click1', () => console.log(2222))// 监听发射器  必须先监听
// //prepend 自动成为最先监听 
// // emitter.removeAllListeners('click1', 'click2')
// //移除 click1和click2 的所有监听器 不再监听事件
// //不传参 默认移除所有 监听器

// //还有一些可以设定 最多监听 几次的函数

// emitter.emit('click1', '99', 33, 22, 11);//使用 后发出事件
// emitter.emit('click1', '99', 33, 22, 11);//使用 后发出事件

// console.log(emitter.eventNames());//[ 'click1', 'click2' ]
// //获取 所有 正在监听的事件

// console.log(emitter.listenerCount('click1'));//[ 'click1', 'click2' ]
// //获取  指定监听的事件 监听的个数
// console.log(emitter.listeners('click1'));//[ 'click1', 'click2' ]
// // 获取 指定监听的事件  绑定注册的 所有(可能有多个) 回调函数




/**
 * 接下来 讲 npm
 *
 * 1.共享你的代码
 *   我们可以通过 commonjs 或 ESModule
 *   将 js 分成 一块 一块的
 *
 *   得益于此,在以后的开发中
 *   我们可以将 自己的代码
 *    以模块化封装,甚至封装成 工具(轮子)
 *
 *    这个工具 我们可以让同事通过导入的方式
 *    来使用 甚至你可以分享给
 *    世界各地的程序员使用
 *
 *    方式总结:
 *        1. 上传到gitHub
 *            缺点是需要知道网址
 *            需要手动引用,并管理相关的依赖
 *            当遇到版本升级或切换时,需要重复上面的操作
 *            显然,上面的方式是有效的
 *            但是这种传统的方式非常麻烦
 *            并且容易出错
 *
 *         2. 使用一个相对专业的工具来管理我们的代码
 *            我们通过工具将代码发布到特定的位置
 *            其它程序员直接通过工具来安装
 *            升级,删除,我们的工具代码
 *
 *            这个工具 就是 npm
 *             https://www.npmjs.com/
 *             https://www.npmjs.org/
 *
 *          主页 搜索 axios
 *           点开 后可以看到 axios 的相关信息
 *           下载量,
 *          一共多少个文件
 *           当前版本,
 *             开源协议,
 *            包的大小
 *           当前有多少人提问
 *
 * 组件
 * 以及github 地址
 *
 * 还有对应文档
 * 文档中也有非常多详细的
 * 关于 axios 到底如何使用的
 *
 * axios 是如何上传到 npm里的呢
 * 后面会讲 我们会自己开发一个脚手架工具
 * 让后将其上载 到npm 网上
 *  我们就可以通过自己的 脚手架工具 快速搭建 项目
 *
 * 除此之外
 * 还需要讲另外一个东西
 * 上载并不是这个网站 https://www.npmjs.org/
 *  这个网站只是展示的官网
 *
 *  并不会储存
 *  真正储存的位置在 registry 仓库
 *  registry.taobao.org
 *
 * cnpm 是什么意思? 后面会讲
 * npm install cnpm -g
 * 使用 cnpm 下载的是非淘宝国内镜像
 *
 * 关于 npm 的配置文件
 *
 * 不管前端与后端
 * 事实上每个项目
 *   都有 配置文件
 *
 *  java ,go , node
 * 一般都会有 对应的配置文件
 *
 * 在前端 node 配置文件就是
 *
 * pack.json
 *
 * 这么个配置文件
 * 记录着项目信息 版本号
 * 项目描述
 * 项目的一些其他库的依赖
 * 并且 也包括库对应的版本号
 *
 * 版本号 后面也会讲到的
 *
 * 自己创建pack.json
 * npm init //描述或管理我们的项目
 *
 * 名字: 回车
 * 版本号:回车
 * 描述:回车
 * 入口:回车
 * 测试时运行哪个指令:回车
 * github仓库:回车
 * 关键字:回车
 * 作者:回车
 * license:回车
 *
 * 确认:回车
 *
 *
 * npm init -y //直接选项一切 默认回车
 *             //可能由于 文件夹名不适合做包名会报 name 的错误
 *
 * npm publish //发布npm 命令
 *
 * 在vue-cli 中 webpack 中配置 入口文件 index.js 是没什么意义的
 *
 * webpack 会自动配置一个 入口文件
 *
 *
 * npm install --production
 * 只会安装 运行时 依赖
 * 去掉了运行时不需要的 开发 依赖
 *
 *  "axios": "^0.21.1"
 *       ^主版本号.次版本号.修订版本
 *       ^ 表示 主版本        不变 更新至最新版
 *       ~ 表示 主版本,次版本 不变 更新至最新版
 *
 * 接下来
 * 具体讲一下
 * 关于
 * npm install
 * 命令
 *
 *     npm install yarn -g
 * //一般 全局安装的都是一些工具 比如像 yarn /webpack /gulp
 *
 *     npm install axios(重要)
 *     npm i axios
 * //安装为 开发时和生产时 依赖
 *
 *     npm install webpack --save-dev
 *     npm install webpack -D
 *     npm i webpack -D(重要)
 * //只安装为 开发时依赖
 *
 *
 * npm install 的原理
 * 除了 package.json
 * 还有个 package-lock.json的
 *
 * npm 5 开始支持缓存策略了
 * 我现在是 6.4.1
 *
 * 他会检测   package-lock.json 依赖锁定的版本
 * 是否 符合 package.json中的 范围版本
 * 符合就会查找缓存
 *
 *
 *
 *
 * 解析 package-lock.json
 *  为什么安装了 axios 一个包
 *  现在却有两个包
 *
 *  因为 axios 的 开发时和生产时依赖
 *  有用到这个follow-redirects 包
 *
 *  实际的版本 也记录在  package-lock.json 里
 *
 * npm config get cache//获取缓存目录
 * C:\Users\Administrator\AppData\Roaming\npm-cache
 *
 *
 *
 * 补充 : 卸载 npm 包
 *
 *   卸载某个依赖
 *    npm uninstall axios//都有
 *    npm uninstall axios --save-dev //开发时 不指定也能卸载 指定的包
 *    npm uninstall axios -D//开发时 不指定也能卸载 指定的包
 *
 * 强制重新构建
 * npm rebuild //根据 package.json
 *
 * 清除缓存
 * npm cache clean
 *
 * npm的命令其实还有很多
 * https://docs.npmjs.com/cli/v7/commands
 *
 *
 *
 * 关于 yarn
 * 关于
 * yarn.lock
 * 那 yarn 和 npm能否作用于同一个 项目里呢
 *
 * npm 是 package.json
 * 而yarn 是自定义的一种格式
 *
 * 效果是差不多的
 * 他们存在一些微小的差异
 *
 * yarn 起初是为了弥补 npm 无法缓存的问题
 * 但是现在 npm 5以后 都支持 缓存策略
 * 但是有些人 习惯了 yarn 就一直使用着
 *
 *
 *
 * 关于 cnpm
 * 1.不喜欢改 淘宝 镜像
 * 2.淘宝 镜像虽说 10分钟更新一次 但是也有可能更新不及时
 * 3.淘宝 镜像有可能不维护了
 *
 * ...感觉好傻
 * 下载 cnpm 不给 npm 设置淘宝镜像 给 cnpm设置淘宝镜像
 * ... 这不是多次一举吗
 *
 * 我的cnpm现在是7.0 地址是 registry=https://registry.nlark.com
 *
 *
 *
 *
 *
 *
 * 关于 npx
 *   npx 工具是在npm5.2 之后自带的一个命令
 *
 * npx 的作用非常多
 * 但是比较常见的是
 * 使他来调用项目中的某个模块的指令
 *
 * 比如 我全局安装了 webpack 是 5.1.3
 * 项目安装的是 webpack  是 3.6.0
 *
 * npx webpack -v//会优先 显示局部的版本
 * 否则直接 webpack -v  显示的是全局的webpack
 *
 *
 *
 *
 * 关于项目创建
 * vue create demo//创建基本项目
 * //1.不会划分目录结构
 * //2.不会有基本配置 vue.config.js
 * //3.肯定没有 axios
 * //4.肯定没有 element-ui,AntDesign
 * //5.也没有 router 的配置
 * //6.也没有 vuex
 *
 * 我自己搞了个项目配置
 * 把他放到了 github上面
 * 或者说 gitee 或公司仓库
 *
 *
 * 或者
 * 安装一个工具
 * 这个工具在 npm镜像库里
 *
 * 比如我现在 开发一个工具 叫 coderwhy
 *
 * 然后 所有人都可以用
 * npm i coderwhy -g
 * coderwhy create 项目名// create 是自己定义的
 * 快速构建
 *
 * 然后就会 从我的仓库里面
 * 把我的代码 下载到目录里面
 *
 *
 *
 * 2021 7 17
 * 关于脚手架
 *
 * 一般是高级工程师
 * 或架构师来做这种事
 *
 * 或者说写一个开源工具
 * 需要做这个事情
 * 一般情况下
 *
 * 初级前端工程师
 * 中级前端工程师
 * 相对来说比较少会写这种东西的
 *
 *  学习这个至少需要 1-2年的开发熟练度
 *
 *
 *  首先查看老师的 coderwhy 版本
 * coderwhy -v
 *
 * npm uninstall coderwhy -g//全局卸载
 * npm i coderwhy -g//全局安装
 * coderwhy create 项目名 //其实是从github中 下载 hy-vue-temp 项目的所有内容
 *
 * vue的脚手架 也只是在帮你拉取 github 上的模板而已
 * 创建(拉取好项目) 之后
 *
 * 还可以在此基础上 追加
 * coderwhy addcpn 组件名 //在组件目录 自动拉取了一个组件模板
 * coderwhy addcpn 组件名 -d src/pages/home  //从指定目录中 拉取一个 固定组件模板
 * coderwhy addpage 目录名 //在pages目录 自动拉取了一个 固定组件目录模板(含 同名.vue 和router.js)
 *                         //router.js 是为了配合 老师写的 自动加载 pages目录下的路由
 *                         //老师自己并没有 写完整路由 而是由node.js 去读取
 *                        // context 读取目录上下文 遍历出 keys 所有文件名
 *                        // 遍历 文件名字 去掉 点 拼上路径并 返回
 * 我觉得不会用到 这个 //多理解一种思路未尝不是一件好事
 *
 * coderwhy addstore 目录名 //在store/modules目录中
 *                          //自动拉取了一个 固定组件目录模板(vuex的index.js 以及 types.js(全局变量管理))
 *                         //index.js中有 state mutations actions getters
 *                         //和 namespaced:true 使用命名空间分割 store 模块成许多小模块 的
 *
 * coderwhy addstore 目录名 -f // 甚至可以规定 划分多少个小模块
 * 
 * 打起精神好好学
 * 我相信这个提升对你的提升是非常大的
 * 
 * 刚才是我已经演示了我写好的脚手架
 * 他的一个使用过程
 * 
 * 接下来的话
 * 我们就看这个东西到底是怎么开发出来的吧
 * 
 * 我带着大家
 * 来做一下这个东西的话
 * 同学们我这里
 * 已经提前创建好
 * 一个项目了(空文件夹)
 * 
 * 大家肯定好奇
 * 敲一个 coderwhy 
 * 是如何 
 * 做到下载东西的
 * 
 * 假设
 * 现在我 why --version
 * 就应该能看到版本号
 * 
 *  why --help
 * 应该能看到 
 * 很多的提示信息
 * 
 *  总之我们
 * 先做第一个功能
 * 我们在这里写某个
 * 指令之后                 
 *        
 * 如何让
 * 这个指令显示
 * 一些东西
 * 
 * 怎么让指令生效
 * 我们创建自己的项目
 * 它肯定有
 * 自己的入口文件
 * 
 * 那入口文件不用多说
 * 就是index.js文件
 * 
 * 另外的话我说过
 * 你肯定需要单独文件
 * 管理项目的整个
 * 依赖/版本号/作者/仓库
 * 等等一大堆东西
 * 
 * 实际上形容的就是
 * package.json 
 * 
 * 你肯定需要他来管理
 * 项目的相关信息的
 * 
 * 所以的话
 * 我这里
 * 得有这么个文件
 * 也就是说 
 * 想要 有package.json 
 * 
 * 1.就得 npm init -y
 * 
 * 2.然后得到了 package.json 并在之中
 * "main": "index.js", 
 * "bin": {
 *   "why": "index.js"
 * },
 * 
 * 3.创建index.js 并在之中
 * #!/usr/bin/env node
 * console.log('why cli');
 *
 * 4.然后在该项目根录中 进入 打开黑窗口
 * 输入 npm link 回车
 * 
 * 然后 再输入 why 回车
 * 就会 执行 index.js 文件 
 * 打印出 why cli
 *
 * 
 * 接下来我们将实现更多
 * 指令 比如 why --version 
 * 显示 版本号
 * 
 * 现在 why 不管后面跟什么
 * 都会 执行 inde.js
 * 
 * 那么 --version 是不是会作为
 * 参数 传入  inde.js 呢
 * 
 * commander 依赖中的
 * program.parse(process.argv);
 * 有此项功能
 * 
 *   
 * 许多 指令并不是从零开始写的
 * 在 github 有一个叫 commander 的库
 * 
 * 也是 tj 开发的 
 * 所以 tj 真的对于我们整个前端来说
 * 贡献非常大的一个人
 * 
 * 还有中文文档可选
 * vue的cli 也是用了这个来完成后续很多工作
 * 
 * 
 * commander: 
 *         npm install commander//安装此库
 *         
 * 
 * 我觉得我不会有发布 npm的机会 所以暂时跳过此处
 * 我觉得就 剩下第八集 是我需要的知识
 * 
 * 讲事件循环的
 * 现在是看完了1-7集 第44分钟56秒
 * 
 * 接下来开始时间轮循 第9集90分钟开始 10集79分钟 结束
 * 
 * 事件循环/轮循 和 异步IO 
 * 
 * 事件循环:
 *         指 js代码受js引擎解析后
 *         与 
 *         (js引擎)载体中其它
 *         非js引擎api的一种沟通
 * 
 * 行为特征:
 *         浏览器: window/dom对象的所有api都是
 *         node : 所有非v8引擎的其它模块api都是
 *        
 * 沟通方式:
 *          回调函数
 * 
 * 进程:
 *      启动一个应用程序
 *      就会默认启动一个进程(也可能是多个)
 * 
 * 线程: 
 *      每一个进程中,都会启动一个线程
 * 
 * 所以我们可以说进程是线程的容器
 * 这个线程被称之为主线程
 * 
 * 
 * 操作系统像一个工厂
 * 工厂中里有很多车间,这个车间就是进程
 * 每个车间可能有一个以上的工人在工厂,这个工人就是线程
 * 
 * 早期 dos 系统是单进程的
 * 
 * 操作系统是如何做到同时让多个进程(边听歌,边写代码,边查阅资料)
 * 同时工作呢
 * 
 * ① 这是因为CPU的运算速度非常快,
 *    他可以快速的在多个进程之间迅速切换;
 * 
 * ② 当我们的进程中的线程获取到时间片时,
 *   就可以快速执行我们编写的代码;
 * 
 * ③ 对于用户来说是感受不到这种快速的切换的;
 * 
 * 所谓多进程 是计算机快到极致所产生的 一种现象
 * 实际上还是 一个脑子运转
 * 
 * js 单独在一个线程内执行
 * 可以把
 * 线程
 * 看成是
 * 一条执行路径
 * 或者一个
 * 执行单元
 * 
 * 这个执行单元就可以执行里面的代码
 * 但是
 * js 所处位置是单线程的
 * 意味着
 * 一个执行单元
 * 
 * 意味着执行 第二步的时候 
 * 不能同时执行 第一步
 * 
 * 假如 某一件事情非常的耗时
 * 那么 就会阻塞后面的代码
 * 
 * 所以 js 不能做耗时的操作
 * 
 * 不是有 异步吗???
 * 异步是 非 js引擎的
 * 是 windows的(在事件队列) 事件循环
 * 
 * 所以这异步不是真正的 js引擎异步
 * 
 * js引擎  单线程   先进后出(坛子)
 * windows 事件队列 先进先出(管子)
 * 
 * 请注意: 
 *        不管怎么进出 后续代码会继续执行
 * 
 * 假设我延时 1万秒
 * 难不成还会挡着 onclick 事件的触发不成
 * 所以这个 进和出 只是指栈的内存释放
 * 
 * 可能只是当到了内存释放 而已
 * 并不会挡着执行
 * 
 * 内存不释放会 导致内存泄漏
 * 所以要 尽可能清空定时器
 * 
 * 
 * 宏任务和微任务
 * 其实 上述 两种 进出方式的操作
 * 
 * 我们统称为宏任务
 * 
 * 宏任务会被加到 宏队列里面
 * 
 * .then的回调是微任务 
 * 被加到 微任务队列里面
 * 
 * 宏任务 : 非js引擎的其它载体api
 * 微任务 : .then 或 自己加的queueMiceotask(()=>{'创建微任务'})
 * 
 * (优先释放内存)所有微任务队列
 * 
 * 才会(释放内存)宏任务
 * 每(释放内存)一个宏任务 又会 判断微任务
 * 
 * 内存释放: 指 回调函数 返回给 js栈执行
 * 真正的(内存释放) 后的执行顺序
 * 1.script 栈
 * 2.微任务
 * 3.宏任务(且不断判断是否新增了微任务)
 * 
 * 以上是 浏览器的事件循环
 * 
 * 接下来讲node的事件循环
 * 我觉得 不必 了解node.js的事件循环了
 * 因为我是前端啊 
 * 看到 第十集 06:30 结束
 * 
 * 
 */


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qwer22215

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值