Little H title

this is subtitle


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 公益404

操作系统启动过程

发表于 2019-10-03 | 分类于 os

操作系统启动过程

先过一遍阮一峰的计算机是如何启动的?
知道了BIOS,MBR,GRUB,kernel,init

BIOS

BIOS中包含两块

  1. POST
    1. 硬件自检,检查CPU,内存,显卡,鼠标外设,所以这个不是加载到内存中的。
  2. 启动顺序
    1. 决定从软盘,CD-ROM,硬盘或网络启动。

MBR

从例如只检测到硬盘,然后动硬盘的第一个001扇区读取 512B的数据,这就是MBR。
3部分结构,

  1. 那第一部分的GRUB和装在/boot/下有什么区别。
  2. 第二部分就是分区表
  3. 第三部的是在BIOS中启动顺序用到的

GRUB

用grub来决定进入那个内核,有1 1.5 2 三个阶段


从 BIOS POST => MBR => GRUB => kernel => init => runLevel

linux.png

  1. BIOS: POST and gives control the BOOT Device and loads MBR (在选择的设备比如硬盘的第一个扇区,512B的MBR)
  2. MBR executes the Boot Load
  3. Grub Menu List
  4. Grub loads Kernel and Initrd
  5. Initrd initial root filesystem
  6. Kernel loads the actual root files
  7. /sbin/init is executed
  8. checks runlevel in /etc/inittab
  9. runs all the files present in /etc
  10. run /etc/rc.local

首先大致知道整个系统的启动过程,然后要知道细节,具体从哪个地址到哪个地址,CPU控制权哪个程序交个哪个程序。
直到登录。进入系统。

CPU读取到CS:IP的值是FFFF0H, 然后这个地址在内存中到末尾就16B,所以只有一个跳转指令。跳转到BIOS中

X86系统20个地址总线 8或16个数据总线。
然后知道显卡也是有BIOS的了。
磁盘的第一个扇区的大小就是512B MBR,最外面开始存。 “0”磁道检测器
加载到内存的7c00处,磁盘可不是固件。
BIOS 将启动磁盘中的第 1 个扇区(MBR 扇区,Master Boot Record)的 512 个字节的数据加载到物理内存地址为 0x7C00 ~ 0x7E00 的区域,然后程序就跳转到 0x7C00 处开始执行,至此,BIOS 就完成了所有的工作,将控制权转交到了 MBR 中的代码。

“盘面”、“磁道”、“柱面”和“扇区”的含义逐一进行介绍。

POST不放入内存,固件就在固件中执行,而从磁盘中读取的MBR就会放入内存中。

实模式和保护模式。 实模式下可以直接访问物理地址。在保护膜实现是访问虚拟地址。

疑问:通电后到底是从哪个地址开始(实模式下应该是直接找物理地址),
CS:IP 到地址FFFF:0000 还是F000:FFF0,或者还是直接到BIOS中了,
然后有一跳跳转地址的,这是跳转到BIOS中吧
POST后还有中断的吧

Grub的具体过程看Linux Boot Sequence
/boot/grub2/grub.cfg


启动登录后boot log后是在/var/log/
dmesg命令也能给你登录信息

最后的runlevel是6个level
/etc/inittab
runlevel也是个命令,可以看当前是在哪
默认的在/etc/init/文件夹下的rc-sysinit.conf //ubuntu
start up script, sk开头的
就是那个rc.d 文件夹 在/etc/下, 里面有s和k开头的

参考

计算机是如何启动的?666
Linux 的启动流程
Linux Boot Process
Understanding the Linux Boot Process - CompTIA Linux+, LPIC-1
BIOS启动过程
Linux系统启动过程分析
BIOS执行位置的问题
The BIOS/MBR Boot Process
How BIOS Works 666
深入解析硬盘结构 666
硬盘概念:扇区,磁道,磁头,柱面,簇
Linux 引导过程内幕 666
BIOS 传统模式下的 X86 PC 启动过程
Basics of the Linux Boot Process 666 主要讲登录runlevel这里开始
Linux Boot Sequence

HTTP协议入门

发表于 2019-07-14 | 分类于 网络

HTTP协议入门

找到一份很不错的入门系列

自己也看了rfc中关于HTTP1.0的, 0.9就别看了, 最后是1.1的补充
然后是2.0的

参考

HTTP协议 (一) HTTP协议详解
HTTP协议2之基本认证—转
HTTP协议3之压缩—转
HTTP协议 (四) 缓存
HTTP协议 (五) 代理
HTTP协议 (六) 状态码详解
HTTP协议 (七) Cookie

fidder4使用

发表于 2019-07-14 | 分类于 前端

fidder4使用

参考

Fiddler4抓包工具使用教程一
Fiddler 4 的常规使用- Windows
Fiddler 教程

git入门中

发表于 2019-07-13 | 分类于 前端

git 入门中

git 入门只需要知道在本地的config, add rm diff commit, push到自己的origin库中这些
中级就涉及和fork的库进行协同开发, 子模块的更新

对于掌握一些 git 命令基础的情况下,总结.
常用git命令总结

刚入手的电脑装完 git 后配置

1
2
3
git config --global user.name 'username'      // 用github就填你github的昵称, 公司内部的就填你真正的名字
git config --global user.email 'user@xx.com' // 同理
ssh-keygen -t rsa -C "youremail" // 将~/.ssh/id_rsa.pub的内容放到你远程库上的SSH key中, 这样就可以push上去

开发人员一般再去远程库上 clone 下来, 而不是本地推上去一个新的(建议用 clone)

1
2
3
4
5
6
git clone git@xxx.com:yourname/project.git     // 注意不是http的, http的push时要输密码的
cd project
vim readme.md
git add readme.md
git commit -m 'add readme'
git push -u origin your-branch

以上只是在自己开发, 在公司私有库开发要先 fork 公司的代码到自己的 github 库中

1
2
3
4
5
6
7
8
9
10
11
12
git clone git@xxx.com:yourname/project.git     // 还是从你的github账号中fork的库
cd project
vim readme.md
git add readme.md
git commit -m 'add readme'
// 一种push
git push -u origin your-branch // push到自己的远程库后, 然后提pr
// 常用的另一种方式, 推荐
git remote add upstream git@xxx.com:yourcompany/project.git // 加了这个主要是为了提交前同步
git remote update upstream // 提交前保持最新, 防止冲突
git rebase upstream/develop
git push -u upstream your-branch // 也不是origin, 这样你就直接可以去upstream的仓库中找到你提交的分支信息(一般直接在项目库首页, 不需要专门点到branch, pr中),再点pr了, 当然在你的origin中也是有这个分支的

注意, 在你想推倒远程的分支上第一次 push 时要加-u,某些公司内部仓库需要每次 push 都加, github 只要一次. origin 和 upstream 这个可以在 git remote -v 中看, 一般 origin 就是你 clone 的地址(git branch -a也可以看), upstrea 是 fork 的地址, 没有就git remote add. 最后的 branch 是你想推到远程的 feat, hotfix 分支. -u 这个操作也可以在 checkout 新分支时用 git branch -u指定, 这样就不用-u 了.
在 github 中一般 origin 指你自己账号下的库, upstream 指公司开发的那个库 clone 源头
一般开发人员在 push 前需要更新最新分支, 防止冲突, 命令git remote update 在 git rebase origin master. git fetch upstream 也一样, 第二种增加远程分支主一方面是为了提 pr 方便, 但重点是同步下远程分支, 防止冲突
那什么时候用git merge 呢, 比如你想拉别人的 branch 就可以用 git pull 而不是 git rebase

一般只会 clone 下第一个分支, 如果要别的分支呢, checkout 一个出来就好

1
git checkout -b dev upstream/dev

本地 push 一个新的到远程(可不看, 只是针对自己的库)

1
2
3
4
5
6
cd existing_folder
git init // 一般都早init了 不需要这个
git remote add origin git@xxx // origin是你自己设置的远程库
git add .
git commit
git push -u origin master

其他常用操作

查看配置问题 git config —list

1
2
3
4
5
6
7
8
1. git config --list                    // 列出所有配置
1. git config --system --list // 所有用户/etc/gitconfig
2. git config --global --list // 当前用户~/.gitconfig 使用git前的配置
1. git config --global user.name "yourname"
2. git config --global user.email "youremail@cc"
3. git config --global core.editor vim
4. git config --global merge.tool kdiff3 // 差异分析工具
3. git config --local --list // 当前项目.git/config,向上覆盖

打 git 命令后不想弹出新的窗口用 git config --global core.pager 'less -FXR'

status

git status 就常用了, 看状态, 有些参数也可以研究下

add 中的操作, 到暂存区

. 是用来表示当前目录
注意这里主要说的是添加 add 到暂存区, git rm有从暂存区删除的功能, 也有只删除文件, 但还是需要 add 下的

git add -i 可以看到用交互时, 但不推荐这么操作, 太影响使用了.

1
2
3
4
5
1. git add [参数] <filename>
1. git add . // 不加参数默认将修改的文件和未跟踪新添加的文件添加到git的暂存区, **也包括删除的**, 注意git2.0开始就包括删除的了. 等同于 git add -A, 要想达到原来的效果用 git add --ignore-removal
2. git add -u // 将跟踪的修改或删除的文件添加到暂存区, **不包括新建的文件**
3. git add -p <filename> // 按选择对一个文件中的某些修改代码块进行分次add, 实现多次提交
3. git add -f <filename> // 强制添加, 而不管.gitignore中的设置

rm 删除操作

git rm删除文件, 但还是需要 add 下的, 也有从暂存区删除的功能, 解除追踪 unadd

1
2
git rm <filename>
git rm --cached <filename> // 抵消git add的操作

移动 mv, 不要自己手动移动

移动和改名, 记得 git mv, 手动移动会导致 git 记录问题

commit

git commit 就是注意按 angular 的注释规范来, 最多用的参数是 —amend. -m 就不用了

分支的问题

1
2
3
4
5
6
7
1. git branch [<branchname>]                    // 不加参数就是列出全部分支, -a是显示远程, 只有分支名就是创建
1. git branch -v // 显示sha1和commit的注释
2. git branch -d <branchname> // -D强制删除
3. git branch -m <branchname> <newname> // 改名
4. git branch -u <url> [name] // 设置upstream, 没有name就是当前分支
2. git checkout <branchname>
1. git checkout -b <branckname> // 一般创建并切换就用这gco -b <>

stash

暂存区, 经常用到

1
2
3
4
5
6
git stash list            // 列出暂存区有哪些
git stash save 'comment' // 给暂存进去的加个名字
git stash apply stash@{n} // 使用, 但不删除
git stash pop // 使用最近一个, 并在暂存区中删除
git stash drop // 删掉某一个
git stash clear // 清空暂存区

diff

很少用, 一般用 vsc 上的功能看

remote

1
2
3
4
5
6
git remote -v                         // 看下有哪些远程
git remote show <name> // 某个远程仓库具体的信息
git remote add origin git@.. // 添加, 用来保持更新
git remote remove <name> // 删除
git remote rename <oldname> <newname> // 改名
git remote update [name] // 更新远程库

添加子模块 submodules

在一个 git 项目中需要使用到另一个 git 项目, 如何将两个项目单独处理并且有需要在其中一个使用另一个.

一般从远程 clone 下来后处理下并不会下载子模块的内容(只是个空文件夹, 并且有 .gitmodules文件), 要 git submodule 下, 看项目中有没有 .gitmodules 就知道了

2 种方式 clone, 一种是递归的方式 clone 整个项目, 另一种是先 clone 父项目在 clone 子模块.

1
git clone git@lll.git --recursive   // 一种就是在clone父项目的时候带00recursive参数就好, 那么子模块就会自动clone下来
1
2
3
git submodule           // 查看子模块, 如果是 `-` 开头的, 那么说明是个空文件夹, 单独clone子模块就要先初始化 git submodule init 再 update
git submodule init // 用来初始化子模块的本地配置文件
git submodule update // 合并起来就是git submodule update --init --recursive

子模块作为工作目录中的一个子目录,但 Git 还是会将它视作一个子模块

本项目添加一个新的子模块

1
2
3
4
git submodule add git@...git [path]   // 将其他一个项目作为一个子模块添加到path中, 然后你就会多一个你指定的文件夹和一个.gitmodules
git submodule // 查看子模块, 如果是 - 开头的, 那么说明是个空文件夹, 要先初始化 git submodule init 再 update
git submodule update
git submodule update --remote

更新 submodule 的 URL

git submodule update --remote <yoursuboduleName>

  1. 更新.gitsubmodule 中对应 submodule 的条目 URL
  2. 更新 .git/config 中对应 submodule 的条目的 URL
  3. 执行 git submodule sync

删除子模块, git 不支持直接删除 submodule 的操作

  1. 执行 git rm --cached {submodule_path} 以及 git rm {submodule_path}。注意,路径不要加后面的“/”(加了表示删除文件夹内文件,不是删除整个文件夹)。例如:你的 submodule 保存在 supports/libs/websocket/ 目录。执行命令为: git rm —cached supports/libs/websocket
  2. 使用 vim 编辑.gitmodules(vim .gitmodule), 删除对应要删除的 submodule 的行.或直接删除.gitmodeuls 文件
  3. 使用 vim 编辑.git/config,删除有对应要删除的 submodule 的行.

参考

GitHub Pull Request 入门
阮一峰的 git 666666
git submodule 的简单介绍
使用Git Submodule管理子模块
Git 子模块:git submodule
7.11 Git 工具 - 子模块

Building-C-Projects

发表于 2019-05-31 | 分类于 c教程

Building-C-Projects

通常情况下,我会从构建的第一步开始,然后从那里往后解释。 然而,在构建C时,如果按给的列表内容的顺序看的话实际上是非常令人感到混乱; 许多步骤只是为将来的步骤而做的准备,也没有必要事先解释他。 因此,我将从中间步骤开始,从那里开始向后和向前解释。 但是,在解释前,我先按顺序列出这些步骤(这个顺序不是一成不变的,但是使用它是合理且合理的):

  1. Configuration
  2. Standard directory detection
  3. Source file dependency calculation
  4. Header file location
  5. Header precompilation
  6. Preprocessing
  7. Compilation and assembly
  8. Object file dependency calculation
  9. Linking
  10. Installation
  11. Resource linking
  12. Package generation
  13. Dynamic linking

大多数构建系统处理此列表中的步骤3,5到7,9和10(将其他步骤在构建之前或之后就手动完成了)。 aimake 目前处理1到11并且在12开始。步骤13几乎总是由操作系统处理。

而现在,这篇文章的主体,描述了构建本身。

6: Preprocessing

一个贯穿本篇文章的例子, 用c写的 Hello, world!

1
2
3
4
5
6
7
#include <stdio.h>

int main(void)
{
fputs("Hello, world!\n", stdout);
return 0;
}

现在,我想让你关注下#include <stdio.h>这行。 C新手之间经常会犯的一个常见误解是认为它与库有关,认为通常会导致 fput 的定义以某种方式与程序“链接”。 实际上,完全不是这么回事:它用于告诉编译器 fput 和 stdout 是什么类型。 在Linux上,上述程序100%和下面的程序一样:

1
2
3
4
5
6
7
8
9
10
11
struct foo;
typedef struct foo FILE;

extern int fputs(const char *, FILE *);
extern FILE *stdout;

int main(void)
{
fputs("Hello, world!\n", stdout);
return 0;
}

我们在任何地方都没有提到 stdio.h ,但该程序仍然有效。 很明显,它与链接无关。

这里实际发生的是 stdio.h 只是一个表示类型,函数和变量声明的列表,以及一些宏定义。 C标准对编译器如何选择实现这些定义没有任何限制,但实际上,像 stdio.h 这样的头部几乎总是以稍微得扩展的C语言的实现(使用特定于编译器的扩展来执行原本不能直接用C表示的操作。例如根据源程序中的数组长度添加缓冲区溢出校验码。

在这种情况下,我们将FILE定义为一个不完整的类型(编译器不需要知道运行程序的FILE的定义,只是它是某种结构,因为所有理智的编译器都会相同地处理指向所有结构的指针); 将 fput 作为函数从 const char * 和 FILE * 转换为 int ; 和 stdout 作为FILE类型的变量。 extern 意味着这只是一个声明,并且该文件不一定包含有问题的函数和变量的定义。 (当链接器涉及时,我们将看到定义实际上在哪里。)

参考

Building-C-Projects

WebAssembly

发表于 2019-05-31 | 分类于 javascript教程

WebAssembly

需要了解计算机组成原理, 操作系统

从 OS 的原来 0101 写对应某一种 CPU, 然后写汇编, 用编译器来装换, 到高级语言在”编译”, “汇编”, “链接”. 这里会出现不同的 CPU 架构, 指令集不同, 然后 是编译器来识别到最后编译成 对应什么架构 CPU 的机器码么. 高级语言会用 LLVM 来编译成对应底层不同 CPU 架构能识别的机器码.

WebAssembly 字节码是一种抹平了不同 CPU 架构的机器码,WebAssembly 字节码不能直接在任何一种 CPU 架构上运行, 但由于非常接近机器码,可以非常快的被翻译为对应架构的机器码,因此 WebAssembly 运行速度和机器码接近,这听上去非常像 Java 字节码。

每个高级语言都去实现源码到不同平台的机器码的转换工作是重复的,高级语言只需要生成底层虚拟机(LLVM)认识的中间语言(LLVM IR),LLVM 能实现:

通常负责把高级语言翻译到 LLVM IR 的部分叫做编译器前端,把 LLVM IR 编译成各架构 CPU 对应机器码的部分叫做编译器后端; 现在越来越多的高级编程语言选择 LLVM 作为后端,高级语言只需专注于如何提供开发效率更高的语法同时保持翻译到 LLVM IR 的程序执行性能。

ARM 的手机上还有很多不同的处理器, 高通 小米 华为 联发科 三星 苹果.

指令

举个例子,假设有以下 5 盏灯。灯由开关控制着,只有开关两种状态。我们约定 1 表示开灯,0 表示关灯。那么,当电灯管理员得到“01000”这样一组数字时,他就知道了应该开第二盏灯,其他的关掉。

机器码编程是不方便的,程序员想要完成某种计算功能,往往需要从非常庞大的指令表查找到相应的数字功能码。因此,后来人们设计了很多助记符,用有意义的单词来表示机器指令,这就形成了汇编语言。

CPU 的指令集存放在什么地方?Ricky Li 回答 6

CPU 的指令集是软件与 CPU 这两个层级之间的接口, 而 CPU 自己, 就是对于这一套 CPU 指令集的实例化.

软件意义上, “指令集”实际上是一个规范, 规范汇编的文件格式.一条汇编指令与一段机器码是一一对应的. 可以看出来, 指令集的作用, 就是告诉程序员/编译器, 汇编一定要有格式. 支持什么指令, 指令带什么限制条件, 用什么操作数, 用什么地址, 都是指令集规范的内容, 要是写错了, 就无法翻译成机器码.指令集规范汇编, 汇编可以翻译成机器码, 机器码告诉 CPU 每个周期去做什么. 因此, CPU 指令集是描述 CPU 能实现什么功能的一个集合, 就是描述”CPU 能使用哪些机器码”的集合”.

汇编指令集与 cpu 指令集是什么关系?bombless 的回答
更多的讲了标准与实现哦, CPU 指令集是标准, CPU 这个硬件是实现. 同理还有编译器上, 这个编译器也是个实现, 按不同的 CPU 指令集标准来.

从 0101 到汇编 6

汇编语言入门教程
先看下阮一峰的第二段,阮一峰的很好的讲了从开关到打孔纸带, 到使用人能识别的符号即汇编语言的这个过程.

到汇编语言后就多出一个步骤,要把这些文字指令重新翻译回二进制, 这样 CPU 才能识别,这个步骤就称为 assembling,用来处理这个步骤的程序就叫做 assembler。它处理的文本,自然就叫做 aseembly code。标准化以后,称为 assembly language,缩写为 asm,中文译为汇编语言.

注: 每一种 CPU 的机器指令都是不一样的,因此对应的汇编语言也不一样。本文介绍的是目前最常见的 x86 汇编语言,即 Intel 公司的 CPU 使用的那一种。

例如常见的处理器还有 intel AMD ARM 这些, 手机上 ARM 的还有高通, 华为麒麟, 小米松果, 三星, 联发科, 苹果 A 这些. 都不同的.
现在的话你不需要关心不同的汇编语言问题 LLVM 会把一份汇编语言都转换成对应 CPU 能运行的机器指令.

然后看下周荷琴的 微机原理及接口第三版 第 65 页开始的 3-2 指令的机器码表示方式, 讲了对于 8 位的微处理器可以从汇编到机器码通过查表. 对于 8086 这种 32 位的直接查表不行, 要先按指令类型给出编码格式, 再查表得到机器码. 就举了个 MOV SP, BX 指令的例子. 所以你就知道了编译器 assembler 干什么的了. 其实也是按某种方式查表

更进一步是看下intel 指令集
知乎上张盼锋的解释, 讲的十分不错哦. 第 1 个视频,正是汇编语言到机器语言的步骤,在编译器处理此阶段,是直接将 mov 这些汇编翻译为机器码;在计算机执行层面,是 CU 控制单元根据不同的 opcode 产生不同的控制信号(见视频 3)。
汇编语言转换成机器语言,具体在机器这个层面是如何实现的? 知乎

前面我只讲了从编译器处理程序的角度, 没有说计算机执行层面的, 知乎上张盼锋还讲了从执行层面的.

对于我们现在在用的高级语言, 当然也是从汇编语言发展过来, 为了进一步提高开发效率咯. 那高级语言怎么运行呢?

你可能在编写完 C 文件后用 gcc 的时候听过预处理, 编译, 链接 这个. 那编译完后不是成汇编语言了么, 为什么有个链接, 直接从汇编语言到机器指令有这个步骤么?

编译器的工作过程
除了将你知道的用 gcc 进行 -E -S -c 生成 .i .s .o 文件后, 还有其他步骤准备. 建议看英文原文更加详细.

参考

WebAssembly 现状与实战

javascript初中高手册

发表于 2019-05-30 | 分类于 javascript教程

javascript 初中高手册

主要是按初中高三个部分来入门, 按各个章节把 js 的知识点串起来, 并且总结到 ES2018, 主要参考来源是 Flavio Copes的 The javascript handbook, 及其中文翻译 JavaScript 完全手册(2018 版)

目录

  1. JavaScript 编码风格指南
  2. JavaScript 词法结构(构建块)
  3. javascript-变量
  4. JavaScript 数据类型
  5. JavaScript 表达式
  6. 原型继承
  7. 如何使用 JavaScript 中的 Classes(类)
  8. JavaScript 异常处理
  9. JavaScript 中的分号(;)
  10. JavaScript 中的引号
  11. JavaScript 字面量模板(Template Literals)指南
  12. JavaScript 中的 function(函数)
  13. JavaScript 箭头函数(Arrow Function)
  14. JavaScript 中的闭包(Closures)
  15. JavaScript 数组(Arrays)
  16. JavaScript 中的循环(Loops)
  17. JavaScript 中的事件(Events)
  18. JavaScript 中的事件循环(Event Loop)
  19. JavaScript 异步编程和回调
  20. 理解 JavaScript 中的 Promises
  21. 用 async 和 await 编写现代 JavaScript 异步代码
  22. JavaScript 中的 循环(Loops) 和 作用域(Scope)
  23. JavaScript 定时器 setTimeout() 和 setInterval()
  24. JavaScript 中的 this
  25. JavaScript 严格模式(Strict Mode)
  26. JavaScript 中的 立即执行函数表达式(IIFE)
  27. JavaScript 中的数学运算符
  28. JavaScript 中的 Math 对象
  29. 介绍 ES Modules(模块)
  30. 介绍 CommonJS
  31. JavaScript 术语表
  32. JavaScript 介绍

三座大山

  • [ ] 作用域链
  • [ ] 原型链
  • [ ] this

其他事宜

  • [ ] 事件循环
  • [ ] Promise 异步回调, async/await, AJAX, fetch

基本知识

  • [ ] 变量
  • [ ] 基本类型 串, 引号
  • [ ] 引用类型
    • [ ] 数组
    • [ ] 对象
    • [ ] 函数, 箭头函数, 闭包, 作用域链, class, 封装 Object.create prototype new class, IIFE

浏览器中

  • [ ] 事件
  • [ ] 循环各种 for

数据结构

  • [ ] 数据结构
  • [ ] 异常
  • [ ] 分号

模块

  • [ ] 模块 commonjs requirejs webpack 那本

参考

ES5-to-ESNext—自2015以来JavaScript新增的所有新特性

发表于 2019-05-24 | 分类于 javascript教程

ES5-to-ESNext—自2015以来JavaScript新增的所有新特性

参考

ES5 to ESNext —  自 2015 以来 JavaScript 新增的所有新特性

react-虚拟DOM和diff

发表于 2019-05-23 | 分类于 react教程

react-虚拟DOM和diff

参考

深入理解react中的虚拟DOM、diff算法 666
细说业务逻辑 66
原生 JavaScript 的 DOM 操作汇总 6

fetch-API

发表于 2019-05-23 | 分类于 javascript教程

fetch-API

参考

使用 Fetch
【翻译】这个 API 很“迷人”——(新的 Fetch API) 66
深入浅出 Fetch API
统 Ajax 已死,Fetch 永生 #2 666

12…14
Henry x

Henry x

this is description

133 日志
25 分类
135 标签
GitHub E-Mail
Links
  • weibo
© 2019 Henry x