微前端 乾坤
Ts高手篇:22个示例深入讲解Ts最晦涩难懂的高级类型工具
本文基本分为三部分:
第一部分讲解一些基本的关键词的特性(比如索引查询、索引访问、映射、extends等),但是该部分更多的讲解小伙伴们不清晰的一些特性,而基本功能则不再赘述。更多的关键词及技巧将包含在后续的例子演示中再具体讲述;
第二部分讲解Ts内置的类型工具以及实现原理,比如Pick、Omit等;
第三部分讲解自定义的工具类型,该部分也是最难的部分,将通过一些复杂的类型工具示例进行逐步剖析,对于其中的晦涩的地方以及涉及的知识点逐步讲解。此部分也会包含大量Ts类型工具的编程技巧,也希望通过此部分的讲解,小伙伴的Ts功底可以进一步提升!
第一部分 前置内容
keyof
索引查询
对应任何类型T
,keyof T
的结果为该类型上所有共有属性key的联合:
1 | interface Eg1 { |
T[K]
索引访问
1 | interface Eg1 { |
T[keyof T]
的方式,可以获取到T所有key的类型组成的联合类型;T[keyof K]
的方式,获取到的是T中的key且同时存在于K时的类型组成的联合类型;
注意:如果[]中的key有不存在T中的,则是any;因为ts也不知道该key最终是什么类型,所以是any;且也会报错;
&
交叉类型注意点
交叉类型取的多个类型的并集,但是如果相同key
但是类型不同,则该key
为never
。
1 | interface Eg1 { |
extends关键词特性(重点)
- 用于接口,表示继承
1 | interface T1 { |
注意,接口支持多重继承,语法为逗号隔开。如果是type实现继承,则可以使用交叉类型type A = B & C & D
。
- 表示条件类型,可用于条件判断
表示条件判断,如果前面的条件满足,则返回问号后的第一个参数,否则第二个。类似于js的三元运算。
1 | /** |
前端知识点-前端基础
1、列举你所了解的计算机存储设备类型?
现代计算机以存储器为中心
,主要由 CPU
、I / O 设备
以及主存储器
三大部分组成。各个部分之间通过总线
进行连接通信,具体如下图所示:
线结构的示意图,CPU、主存以及 I / O 设备之间的所有数据都是通过总线进行并行传输,使用局部总线是为了提高 CPU 的吞吐量(CPU 不需要直接跟 I / O 设备通信),而使用高速总线(更贴近 CPU)和 DMA 总线则是为了提升高速 I / O 设备(外设存储器、局域网以及多媒体等)的执行效率。
2、一般代码存储在计算机的哪个设备中?代码在 CPU 中是如何运行的?
高级程序设计语言不能直接被计算机理解并执行,需要通过翻译程序将其转换成特定处理器上可执行的指令,计算机 CPU 的简单工作原理如下所示:
CPU 主要由控制单元、运算单元和存储单元组成
(注意忽略了中断系统),各自的作用如下:
控制单元
:在节拍脉冲的作用下,将程序计数器(Program Counter,PC)指向的主存或者多级高速缓存中的指令地址送到地址总线,接着获取指令地址所对应的指令并放入指令寄存器 (Instruction Register,IR)中,然后通过指令译码器(Instruction Decoder,ID)分析指令需要进行的操作,最后通过操作控制器(Operation Controller,OC)向其他设备发出微操作控制信号。运算单元
:如果控制单元发出的控制信号存在算术运算(加、减、乘、除、增 1、减 1、取反等)或者逻辑运算(与、或、非、异或),那么需要通过运算单元获取存储单元的计算数据进行处理。存储单元
:包括片内缓存和寄存器组,是 CPU 中临时数据的存储地方。CPU 直接访问主存数据大概需要花费数百个机器周期,而访问寄存器或者片内缓存只需要若干个或者几十个机器周期,因此会使用内部寄存器或缓存来存储和获取临时数据(即将被运算或者运算之后的数据),从而提高 CPU 的运行效率。
3、什么是指令和指令集?
上图右侧主存中的指令是 CPU 可以支持的处理命令
,一般包含算术指令
(加和减)、逻辑指令
(与、或和非)、数据指令
(移动、输入、删除、加载和存储)、流程控制指令
以及程序结束指令
等,由于 CPU 只能识别二进制码,因此指令是由二进制码组成。除此之外,指令的集合称为指令集(例如汇编语言就是指令集的一种表现形式),常见的指令集有精简指令集(ARM)和复杂指令集(Inter X86)。一般指令集决定了 CPU 处理器的硬件架构,规定了处理器的相应操作。
5、JavaScript 是如何运行的?解释型语言和编译型语言的差异是什么?
解释器和编译器有很多相似之处,都需要对源程序进行分析,并转换成目标机器可识别的机器语言进行执行。编译器
:先把源程序全部转换成机器语言并产生目标文件,然后将目标文件写入相应的程序存储器进行执行(转换和执行的过程分离)解释器
:在转换源程序的同时立马执行对应的机器语言(转换和执行的过程不分离)
①JS代码->解析成 AST (期间伴随词法分析、语法分析)->生成字节码(V8)->生成机器码(编译器)
电脑:CPU+I/O设备+主存储器组成,通过总线进行连接并行传输
CPU:控制单元+存储单元+运算单元
主存:指令,CPU可以支持的处理命令,一般包含算数指令(加减)、逻辑指令(与、或和非)、数据指令(移动、输入、删除、加载和存储)、流程控制指令、程序结束指令等
5.简单描述一下 Babel 的编译过程?
答: 首先,Babel的作用是 从一种源码到另一种源码,充当转换编译器的作用,可以简述为 解析(解析JS代码)->转换(解析和修改AST)->重建(将修改后的AST转换成另一种JS代码)
7.浏览器和 Node.js 中的事件循环机制有什么区别?
在浏览器里,每当一个被监听的事件发生时,事件监听器绑定的相关任务就会被添加进回调队列。通过事件产生的任务是异步任务,常见的事件任务包括:
- 用户交互事件产生的事件任务,比如输入操作
- 计时器产生的事件任务,比如setTimeout;
- 异步请求产生的事件任务,比如 HTTP 请求。
主线程运行的时候,会产生堆(heap)和栈(stack),其中堆为内存、栈为函数调用栈。我们能看到,Event Loop 负责执行代码、收集和处理事件以及执行队列中的子任务,具体包括以下过程。 - JavaScript 有一个主线程和调用栈,所有的任务最终都会被放到调用栈等待主线程执行。
- 同步任务会被放在调用栈中,按照顺序等待主线程依次执行。
- 主线程之外存在一个回调队列,回调队列中的异步任务最终会在主线程中以调用栈的方式运行。
- 同步任务都在主线程上执行,栈中代码在执行的时候会调用浏览器的 API,此时会产生一些异步任务。
- 异步任务会在有了结果(比如被监听的事件发生时)后,将异步任务以及关联的回调函数放入回调队列中。
- 调用栈中任务执行完毕后,此时主线程处于空闲状态,会从回调队列中获取任务进行处理。
- 上述过程会不断重复,这就是 JavaScript 的运行机制,称为事件循环机制(Event Loop)
https://juejin.cn/post/6987549240436195364#heading-0
https://juejin.cn/post/6987070062490288165?share_token=3904e7be-48e7-44bf-a27c-66ab95dd598c#heading-65
https://juejin.cn/post/6844903843197616136#heading-3
手写Promise源码
https://juejin.cn/post/6994594642280857630
1 | class MyPromise { |
阿里云服务器搭建前端服务流程
重置实例密码
重置实例密码之后可以在阿里云后台进行远程连接Workbench,或者试用ssh进行远程连接
这里也可以重置VPC连接,这样就可以在阿里云后台进行远程连接VPC
安装git 和 node
https://help.aliyun.com/document_detail/50775.html
1 | yum -y install git |
注意:使用yum安装的git在/usr/bin/git下
安装nginx
绑定域名,进行访问
从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理
浏览器包含哪些进程
- Browser进程:浏览器的主进程(负责协调、主控),只有一个。作用有
- 负责浏览器界面显示,与用户交互。如前进,后退等
- 负责各个页面的管理,创建和销毁其他进程
- 将Renderer进程得到的内存中的Bitmap,绘制到用户界面上
- 网络资源的管理,下载等
- 第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
- GPU进程:最多一个,用于3D绘制等
- 浏览器渲染进程(浏览器内核)(Renderer进程,内部是多线程的):默认每个Tab页面一个进程,互不影响。主要作用为
- 页面渲染,脚本执行,事件处理等
重点是浏览器内核(渲染进程)
请牢记,浏览器的渲染进程是多线程的
- GUI渲染线程
- 负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。
- 当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行
- 注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(相当于被冻结了),GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
- JS引擎线程
- 也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)
- JS引擎线程负责解析Javascript脚本,运行代码。
- JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序
- 同样注意,GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。
- 事件触发线程
- 归属于浏览器而不是JS引擎,用来控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)
- 当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件线程中
- 当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理
- 注意,由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行)
- 定时触发器线程
- 传说中的setInterval与setTimeout所在线程
- 浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)
- 因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)
- 注意,W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms。
- 异步http请求线程
- 在XMLHttpRequest在连接后是通过浏览器新开一个线程请求
- 将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。再由JavaScript引擎执行。
浅谈前端AST的概念与实际应用
回想日常开发中使用的框架,脚手架,打包工具,再到编辑器的代码补全,代码格式化等功能,用一句话概括他们做的事那就是批量修改源代码,再精确一点即代码转换。既然要转换,那么首先第一步一定是理解源程序。如何能阅读和理解源程序?这就要引出一个关键概念-AST,本文将依次介绍AST的概念,生成过程,基本结构,节点类型,如何操作AST等,最后通过一个AST的实际应用来进行总结。
AST的概念
抽象语法树(Abstract Syntax Tree)简称AST,顾名思义,它是一棵树,用分支和节点的组合来描述代码结构。他可以让计算机理解我们写的代码,我们不妨先试着按自己的理解来想象一下这棵树的构造。例如下面这段代码
1 | function foo(a) { |
分析,首先这是一个函数,有名字(foo),参数(a),函数体(body)三个基本属性。再来看body,他有两条语句,分别是声明语句和return语句。先看声明语句,他由变量b和一条表达式语句组成,表达式语句由三个元素:a,+,1组成。而return语句则由元素b组成。我们可以依照上述并按照节点与分支的组合描绘出这段代码的AST的大致结构如下。
git放弃本地文件修改
1. 未使用git add 缓存代码
使用git checkout – filename,注意中间有–
1 | git checkout -- filename |
放弃所有文件修改 git checkout .
1 | git checkout . |
此命令用来放弃掉所有还没有加入到缓存区(就是 git add 命令)的修改:内容修改与整个文件删除
此命令不会删除新建的文件,因为新建的文件还没加入git管理系统中,所以对git来说是未知,只需手动删除即可
2. 已使用git add 缓存代码,未使用git commit
使用 git reset HEAD filename
1 | git reset HEAD filename |
放弃所有文件修改 git reset HEAD
1 | git reset HEAD |
此命令用来清除 git 对于文件修改的缓存。相当于撤销 git add 命令所在的工作。在使用本命令后,本地的修改并不会消失,而是回到了第一步1. 未使用git add 缓存代码,继续使用用git checkout – filename,就可以放弃本地修改
3. 已经用 git commit 提交了代码
使用 git reset –hard HEAD^ 来回退到上一次commit的状态
1 | git reset --hard HEAD^ |
或者回退到任意版本git reset –hard commit id ,使用git log命令查看git提交历史和commit id
1 | git reset --hard commit id |