/**
* 什么是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 结束
*
*
*/
前端node理解并使用
最新推荐文章于 2024-04-21 11:48:20 发布