前端
2021-05-26 16:38:33 0 举报
AI智能生成
前端知识体系
作者其他创作
大纲/内容
node
前端
BOM/DOM 浏览器对象
XMLHttpRequest/fetch 网路请求
后端
os 操作系统
process 进程
fs 文件系统
rmdirSync() 删除目录
existsSync
判断路径是否存在
existsSync(path) 如果路径存在,则返回 true,否则返回 false
mkdirSync() 同步地创建目录。
readdirSync() 同步读取
readFileSync() 文件读取
statSync() 返回fs.Stats类
fs.Stats类
.isFile()
readFile 读文件异步
toString()可将buffer转字符串
writeFile 写文件异步
JSON.parse()可将buffer转化为字符串
require('readline')命令行接口
util
promisify避免回调地狱
path-路径
format 方法从对象返回路径字符串
dirname 方法会返回 path 的目录名
basename 方法会返回 path 的最后一部分
extname 方法会返回 path 的扩展名
resolve()
net 网络通讯
CommonJS 模块
模块作用域
__dirname
运行
node xxx,js
nodemon
调试
log
断点
Jest 测试
子主题
实战自动化测试
清空测试目录
__dirname读取文件目录
获取文件内容生成测试语句
写入文件系统
缓存
强缓存
Expires
Cache-Control
协商缓存
last-modified
Etag
网络
埋点可以使用img src发送请求,一般都这么做的,轻量,没有跨域
跨域是浏览器单方面的原因,跟服务没有关系,但可以加请求头让浏览器不校验
加入了header触发了预检请求
非正常报头
Set-Cookie
放入浏览器cookie
爬虫
request 请求
cheerio 相当于jquary
cheerio 纯JS字符编码转换
框架
Express
下一代koa
koa2完全使用Promise配合async来实现
next()执行下一个中间件
use使用中间件
router使用路由
像操纵对象一样操纵数据库
sequelize
egg.js
egg-sequelize mysql2 加配置连接数据库
npm
初始化 npm init -y
指定脚本解析器为node #!/usr/bin/env node
sudo npm link链到本地
在终端跑,文件名和package.json里的name一致
promisfy
node工具包里的
clear
清屏
chalk
粉底颜色
ora
loading 转圈圈
download-git-repo
注意下载地址格式:github:tiankongoyll/tianqi
打包上线
cluster包
故障重启
多核利用
多进程共享端口
pm2 node的运维功能
多进程管理
pm2 start app.js --watch -i 2
pm2 logs 查询日志
pm2 list
pm2 stop app 停止name为app的
pm2 kill杀掉整个进程
使用后一定要用这个命令,否则端口还会被占用
.yml
在文件里写参数
pm2 start process.yml
数据库
MySQL
mysql -u root -pxxx 登录
ORM
.sync()
UUID
Sequelize
常用命令
2命令结尾加一定要加分号;
启动docker
GRANT ALL ON *.* TO '用户名'@'%';
show databases;查看数据库
create database kaikeba;创建数据库
MongoDB
启动mongod
mongo
require('mongodb')
insertOne插入
findOne查询
updateOne更新
deleteMany删除文档
开发方法论
原型
EP 实际参照模型
DB
后端代码
api
UI
Sequlize Java ORM
原型
后端开发(领域模型)
API
UI
DB沦为持久化服务
mongoose
create创建
find 查找
updateOne 更新
deleteOne删除
docker启动
启动容器
进入容器修改密码
创建连接 option
KeystoneJS
这是一个基于Node.js的CMS和Web应用程序框架
oracle
sqlserver
OAuth(开放授权)
认证请求
服务器重新定向GitHub认证
Github账户登录
携带code回调服务器
服务器用code去申请令牌
放回令牌
服务器返回浏览器内容
即时通讯
socket.io
前端
socket.on 监听
socket.emit 提交
后端
socket.on
io.emit
Websocket
长连接和短连接
短连接
HTTP/1.0中,默认使用的是短连接。
长连接
Connection:keep-alive
布局
只要一行代码,实现五种 CSS 经典布局
前端安全
XSS
反射 存储
ctx.set('X-XSS-Protection', 0) // 禁⽌止XSS过滤
CSP
转义字符
黑名单
白名单
require('xss')
HttpOnly
禁止读取
短域名
在页面运行JS
img支持跨域,url?携带页面敏感信息
CSRF
防御
验证 Referer
人机图形验证+短信
cookie +hash
Click Injeting
防御 X-FRAME-OPTIONS
DENY
SAMEORIGIN
ALLOWFROM
SQL注入
万能密码
1'or'1'='1
防御
占位,传参
与前端交互的表权限
后端对字符转码
OS命令注入
请求劫持
DNS劫持
http劫持
DDOS
SYN Flood
HTTP Flood
工程化
webpack
webpack.config.js
entry 入口
单入口
多入口
output 出口
单出口
bundle
chunk
moudel
moudel
多出口
setMpa()返回
glob.sync()
loader 模块
rules执行顺序从后向前(右到左)
自定义loader
会接收到文件内容,做处理后返回
函数但不可以是箭头函数,因为需要this
loader必须有返回值
callback =this.async() 处理异步
use对象形式可以用options传参
loader有异步
this.async()
loader查找路径设置
resolveLoader:{//标明去哪儿找loader
modules:["node_modules","./myLoaders"]
},
modules:["node_modules","./myLoaders"]
},
plugins 插件
生命周期
本质是一个类
html-webpack-plugin
配置
自定义插件
类
apply(complier){}
异步钩子
tapAsync来触发
(compilation,cb)
compilation.assets
'xxx':{source:xxx,size:xxx}
同步钩子
tap
compilation
mode 构建环境
production
development
none
打包流程
拿到配置,初始换工作,得到最终配置
实例化一个compiler类注册插件,对应的生命周期绑定相应事件
执行编译,compiler.run
递归处理所有依赖的模块 生产chunk
把chunk输出到指定位置
bundle原理分析
读取配置
入口
从哪个文件开始分析
出口
放到什么位置
叫什么名字
入口函数,run开始编译
处理文件依赖
进入依赖模块
处理依赖模块、处理文件内容,递归下去
依赖图谱 trunk
处理文件内容
借助babel工具 转出成AST(抽象语法树)提取路径
借助babel语法转译
生成bundle文件
以对象的形式处理require的引入及导出
.browserslistrc
兼容浏览器版本
npx browserslist "> 1%"
查看 满足条件的浏览器
npx browserslist "last 2 versions and >1%"
npx browserslist "last 2 versions or >1%"
postcss-loader和autoprefixer可以配置浏览器兼容css
cssnano样式压缩
.npmrc
npx
是在当前目录里的bin文件里找,没有安装
子主题
子主题
HMR热模块替换
new webpack.HotModuleReplacementPlugin(),
hot: true,
css支持特别好
js 会刷新
关掉浏览器刷新
hotOnly: true,
Vue和React的生态已经提供了HMR解决方案
babel
语法转换
新特性
垫片 babel/polyfill
按需加载-配置
.babelrc
优化
构建优化
减少编译体积
ContextReplacementPugin
IgnorePlugin
babel-plugin-import
babel-plugin-transform-runtime
并行编译
happypack
thread-loader
uglifyjsWebpackPlugin
缓存
cache-loader
hard-source-webpack-plugin
uglifyjsWebpackPlugin开启缓存
babel-loader开启缓存
预编译
dllWebpackPlugin && DllReferencePlugin、auto-dll-webapck-plugin
性能优化
减少编译体积
Tree-shaking
Scope Hositing
hash缓存
webpack-md5-plugin
拆包
splitChunksPlugin、import()、require.ensure
Docker
systemctl start docker
systemctl stop docker 关闭
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl restart docker
docker pull nginx 拉取镜像
删除镜像
docker rmi XXX
容器
docker container ls -a 查看
docker logs mysqllx查看日志
docker container rm mysql1删除容器
docker images nginx查看镜像
docker build -t mynginx .
打包镜像,根据本目录下的Dockerfile文件
docker run -p 80:80 mynginx
运行镜像
docker-compose up
启动编排,负载均衡
docker run -p 8000:80 -v $PWD/www:/usr/share/nginx/html -d nginx后台运行
docker ps查询进程
docker ps -a查询所有进程
docker stop e93停止进程
docker start e93启动进程
docke rm c99某个进程
docker exec -it 9a9 /bin/bash进入运行的进程服务内部
cd /etc/nginx/conf.d 查看Nginx配置
vi default.conf
bash: vi: command not found 报错
apt-get update
apt-get install vim
apt-get install vim
exit 退出
持续集成
webhook
pm2 logs看日志
netstat -tunlp查看端口占用情况 netstat -tunlp | grep 3000
kill -9 PID
df -h查看磁盘容量
do'c
env 环境变量
vue
.env.staging
.env.development
.env.production
vue
杨图片
组件化
常见传值
props
$emit/$on
event bus
派发
监听
观察者模式
vuex
传值
$attrs
没有props
v-bind相当于react的...展开
$listeners
传事件
隔代传
v-bind=“$attrs”
传属性
v-on="$listeners"
传事件
多代
provide/inject
inheritAttrs
继承属性如class,false不继承
强耦合性传值
$parent
特定类型或名称,循环向上查找,避免程序脆弱
$children
$root
$refs
访问实例
vue-router
hash #/about
window.addEventListener('hashchange',callback)
History api /about
根据URL显示对应的内容
router-view
数据响应式---重新执行render函数
插件
返回一个函数或一个对象,他有一个install方法
本身是一个插件 new了,她就是一个类
use时会调用install方法
VueX
l实现Store类
维持一个响应式的state
commit()方法
dispatch()方法
挂载$store
Vue-SSR
原理
创建路由工厂函数-为每个请求分配一个路由
main.js-工厂函数,每次请求返回一个新的实例
特点
SEO
首屏渲染
缺点
复杂度
性能
优化策略
缓存:node、Nginx
降级:CPU 内存 SPA
pre-render plugin插件
静态化 nuxt generate
场景
判断请求 -爬虫puppeteer或用户spa
移动端
nuxt.js
原理1
MVVM
数据响应式
Vue
data数据改变驱动视图更新
数据劫持,拦截
Object.defineProperty()
不支持数组
Vue重写了数组的方法
observe
循环和递归
set()
Vue3
代理方式
Proxy
angular
章值检测
React
主动api
源码1级
概念解析
Watcher
执行更新函数(更新DOM)
Compile
编译模板
初始化视图
收集依赖(更新函数、watcher创建)
Observer
执行数据响应式变化(分辨是对象还是数组)
class Vue{}
observe() data响应处理
遍历指定数据对象每个key,拦截他们
递归直到每一个的对象都做了处理 defineReactive
管家创建dep = new Dep()
Dep class
管家:和某个key,一一对应,管理多个秘书,数据更新时通知他们做更新工作
Object.defineProperty
get
// 依赖收集
set
value==对象再observe()
// 通知更新
proxy()代理函数,用户可以访问data
Object.defineProperty()
new Compile('#app', this)编译模板
compile遍历它,判断当前遍历元素的类型
元素
compileElement
编译元素:分析指令、@事件
获取属性并遍历之
text()
html()
文本
判断插值表达式
compileText
源文件追踪
scripts/config.js
src/platforms/web/entry-runtime-with-complier.js
扩展$mount
el < template < render render优先级最高
template编译模板
runtime/index.js
安装平台特有patch函数,diff发生的地方
diff流程
src/core/vdom/patch.js
createPatchFunction()
参数
modules - 属性相关操作 <div id="xxx" @click>
nodeOps - 节点增删改查等操作
patch()
基于Snabbdom
新节点未定义,删除
老节点未定义,新增
通常初始化和更新
更新 patchVnode
Diff所在地
同层比较深度优先
sameVnode()是否是相同节点
key相同
tag相同
input type
比较类型
比的是虚拟,操纵的的是真实DOM
属性更新
文本更新
子节点更新
获取双方孩子
新节点没有文本
text和children互斥的
text和children互斥的
双方都有孩子
重排
updateChildren()
创建4个游标和对应的节点
while循环比较后再调用patchVnode
两个开头相同,游标向后移动一位
两个结束
交叉,老开始和新结束
交叉,两结束和新结束
从这开始首尾没找到,从新的开头拿一个去老的里面找相同的
新老数组一定有一个先结束
初始化处理
初始化首次执行创建,整棵树的创建
createElm
createElm
递归创建节点
自定义组件的处理
createComponent
vnode.data中会有前面安装的管理钩子
(installComponentHooks)
(installComponentHooks)
获取初始化钩子
执行组件的初始化:实例创建和挂载
下一步就是把前面挂载得到的dom插入到父节点中
初始化组件:属性操作
插入到parentElm
处理保留标签
createElement创建原素
父节点创建完成,紧接着创建子节点
createChildren
createChildren
插入子节点
实现了$mount
mountComponent 挂载组件
callHook(vm, 'beforeMount')
updateComponent
new Watcher
callHook(vm, 'mounted')
core/index.js
初始化全局API
initGlobalAPI(Vue)
initGlobalAPI(Vue)
src/core/instance/index.js
Vue构造函数
执行初始化
执行初始化
混入函数
实现了众多的实例和方法
实现了众多的实例和方法
initMixin
扩展了一个_init方法
vue实例
合并选项
各种初始化
initLifecycle
$parent/$root
initEvents监听
initRender
$slots/$createElement
$attrs/$listeners
$attrs/$listeners
callHook调用生命周期钩子
initInjections
获取注入数据
initState
数据初始化data/props/methods/computed/watch
initProvide
给后代提供数据
callHook
钩子
。。。
stateMixin
src/core/instance/state.js
initState
initProps
initMethods
initData数据响应式
observe遍历做响应式处理
每个对象配一个Observer实例
如果一个对象拥有__ob__属性,
他就是一个响应式的数据
他就是一个响应式的数据
new Observer()
this.dep = new Dep()
大管家:未来当前value对象动态添加或删除属性,通知视图更新
比如this.$set(this.obj,'bar','bbrrrrr')
如果是数组,如果有数据动态加入或者移除,通知视图更新
对象
遍历所有key
walk()
定义属性拦截
defineReactive()
defineReactive()
小管家:每个key一个
dep = new Dep()
dep = new Dep()
如果val是对象还会递归它
Object.defineProperty
get
依赖收集
dep.depend()
src/core/observer/watcher.js
watcher里的addDep()
watcher里的addDep()
则建立watcher和dep关系
反向建立dep和watcher关系
if childOb 子ob
如果存在对象嵌套,则存在子ob实例,
需要建立大管家和当前watcher之间的关系
需要建立大管家和当前watcher之间的关系
set
dep.notify()
src/core/observer/watcher.js
数组
protoAugment()
arrayMethods
重构了数组方法
新添加的数组项要做响应式处理
通过ob获取大管家
ob.dep.notify()
ob.dep.notify()
initComputed
initWatch
stateMixin
暴露方法
$data
$props
$set
$delete
$watch
eventsMixin
事件
lifecycleMixin
生命周期
_update
$forceUpdate
$destroy
renderMixin
渲染相关
$nextTick
_render
src/core/observer/dep.js
notify()
src/core/observer/watcher.js
update()
src/core/observer/scheduler.js
秘书入队queueWatcher()
获取秘书id
判断是否已经入队,去重
如果没有在等待状态
尝试异步方式将该函数放入微任务队列
nextTick(flushSchedulerQueue)
src/core/util/next-tick.js
用户传递的回调函数会被放入calbacks里面
前面刷新函数就是执行callback中的所有回调
定时器函数启动
timerFunc()
优先级自上而下选其一
Promise
flushCallbacks
MutationObserver
setImmediate
setTimeout
src/core/observer/scheduler.js
flushSchedulerQueue
关键代码:执行run函数
watcher.run()
watcher.run()
src/core/observer/watcher.js
小秘书真正执行任务函数
run ()
run ()
this.get()
getter
来源
构造watch时传进来的
src/core/instance/lifecycle.js
updateComponent
vm._update(vm._render(), hydrating)
进入方法
_render()得到VNode
update()把虚拟DOM变成真实DOM
new Watcher(vm, updateComponent, noop, {
模板编译
template
render
编译
src/core/instance/render-helpers/index.js帮助方法
src/core/instance/render.js
vm._c
vm.$createElement
编译只执行一次
路径追踪
src/platforms/web/entry-runtime-with-compiler.js
if (template) {
75 compileToFunctions
src/compiler/to-function.js
61 compile执行编译
/src/compiler/create-compiler.js
baseCompile核心编译
/src/compiler/index.js
parse(template.trim(), options)解析生成AST树
解析器
HTML解析器
文本解析器
过滤解析器Vue3废除
src/compiler/parser/index.js
parse
// 其他平台转换函数
// 配对stack
// 开始解析
parseHTML
parseHTML
各种正则
遇到开始标签
生成ast对象
processIf
optimize
优化
generate
src/compiler/codegen/index.js
渲染函数代码生成
递归遍历ast,并且生成对应js代码字符串
genElement
genFor
genIf
93 createFunction
new Function(code)字符串转化为函数
staticRenderFns
静态内容,不需要比对
子主题
dep.notify小秘书通知更新
watcher
updateComponent
render
_update()转化为真实DOM
补丁函数patch
createElement
src/core/global-api
ASSET_TYPES
initAssetRegisters
src/core/instance/render.js
实现Vue.components()/...三个方法
给编译器生成的渲染函数使用
vm._c
用户编写渲染函数使用这个
vm.$createElement
调试追踪
/src/core/vdom/create-element.js
102 if (typeof tag === 'string') {
vnode = createComponent
/src/core/vdom/create-component.js
194 安装自定义组件管理钩子函数
installComponentHooks(data)
installComponentHooks(data)
之后看这_update
src/core/instance/lifecycle.js
src/core/instance/lifecycle.js
之后createElm
/src/core/vdom/patch.js
/src/core/vdom/patch.js
153 createComponent
/src/core/vdom/patch.js
createComponent
createComponent
231 i(vnode, false /* hydrating */)
进入
componentVNodeHooks
子组件 根据组件vnode创建一个组件实例
flowjs语法
图谱
概念
异步更新队列
批量
减少页面更新次数
异步
事件循环
微任务
promise
宏任务
setTimeout
虚拟DOM
对象
树
减少DOM操纵的频率
编译映射到多个平台
vue3
composition API
Teleport
传送
Fragments
不要求单根了
emits['click']
自定义事件不会与原生冲突
custom renderer
自定义渲染器
扩展到不同平台
全局API改为实例方法
避免多个实例公用一个配置方法,测试困难
摇树优化
把api提出来,需要import引用了
减少打包体积
渲染函数API修改
插槽
函数式组件
并没有大的性能提升,不推荐
异步组件
defineAsyncComponent
指令变化
$on,$off 和 $once 实例方法已被移除
$on并不是指对子组件的监听
$attrs
包含传递给组件的所有 attribute,包括 class 和 style。
v-model
的改变
router
addRoute
useRouter()返回路由
useLink
RouterLink
React
组件通信
props
context
React.createContext()
Context.Provider
传值 组件的value <ThemeProvider value={theme}>
value 值存在state里避免前后value值变化对比差异更新子组件
value的变化会引起所有子组件的更新,不要滥用
接收
Context.Consumer
(theContext)=》<div>{theContext.thename}</div>
contextType 类组件
this.context
useContext 函数组件
ref
组件
class组件
render是要渲染UI的,不要没有返回
装饰器只能@装饰类,不能这样用于函数,因为纯在函数提示
生命周期
constructor
获取,起源,状态,表格,传递
getDerivedStateFromProps
应该,组件,更新
shouldComponentUpdate
render
获取,猛然的,射击,前,更新
getSnapshotBeforeUpdate
componentDidMount
componentDidUpdate
componentWillUnmount
函数组件
高阶组件
函数
参数是组件返回值还是组件
组件更新
props、context、state变化
不要在render()里定义组件,因为更新render会重新渲染执行
优化
React 如何避免 rendr 的触发
函数
React.memo
类组件
shouldComponentUpdate
React.PureComponent
API
React.forwardRef
useImperativeHandle
React.cloneElement
克隆组件做修改
ant
from组件
自定义一个hook
定义一个产库
类class
定义一个产库store
定义存储下实例的数组
储存成功失败方法
订阅函数
返回一个取消订阅方法
设置产库的值
设置后要更新组件
获取产库的值
提交函数
校验
方法(暴露可以让外部用的方法)
React.useRef()
创建Context React.createCountext()
From
Field
组件强制刷新 this.forceUpdate();
input
传送门
创建时 增加 appendChild
卸载时 删除 removeChild
createPortal()
Hook
基础
useState
useEffect
不阻塞return返回DOM
useContentext
额外
useReducer
可以配合userFffect(,[state])来实现异步
或使用定时器延迟触发
useCallback
useMemo
useRef
返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。
useImperativeHandle
useLayoutEffect
useDebugValue
原理
函数
接收一个初始值,返回一个数组【值,方法】
TODO
把hook纯在当前fiber上:wipFiber
返回
state
oldHook的或初始
setState
触发重新渲染,生成下一个fiber,从最外开始更新,相当于重新render
状态管理
redux
reduce
javascript方法
reducer 函数方法 通常我们定义规则的这个方法叫reducer,方法名其实可以随意改
纯函数 接收旧的state和action返回新的state
返回state
action 在执行dispatch方法时传的参数叫action
普通对象
函数 必须借助redux中间件
thunk如 把dispatch和getState传入函数
Redux 他只是一些函数方法来辅助修改reducer方法的默认参数state
redux API
store 通常创建的变量名为store但完全可以改
获取厂库getState()
这里是获取的所有的
创建厂库 createStore
参数 规则(reducer)
参数 中间件applyMiddleWare(中间件名称)
事件派发 dispatch(action)
订阅 subscribe(listenter)
bindActionCreators
redux源码
createStore
函数返回方法
获取 getState
修改 dispatch
订阅 subscribe
取消订阅
在订阅数组里去掉那一个 splice(index,1)或filter
applyMiddleware
返回store,同时加强dispatch
Array.prototype.map()
map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。
compose
洋葱圈模型
中间件
中间件都是函数
react-redux
API
Provider
他就加了connect的高阶组件
connect
函数
返回一个揉入state,dispatch的高阶组件
hooks
useSelector()
源码上useLayoutEffect
useDispatch()
源码函数组件的强制更新方法
react-sage
用法
在react-redux里的connect里定义的{type:"XXXX"}指向
action里定义的react-sage的方法
react-sage的方法里的put指向reducer
API
createSagaMiddleware
middleware.run(saga, ...args)
takeEvery(pattern, saga, ...args)
call()
阻塞同步
fork
非阻塞异步
put()
Router
history
react-router
withRouter
访问 history和match 。
类组件用装饰器
函数组件用函数调用包裹
源码
这是个高阶组件,接收一个组件为参数
把Context里的参数也传到组件的props里
解构{...context}
Router
源码
props.history.listen(location)监听改变state引起组件更新
取消监听
利用Context传值
value
history
location
match默认的向下穿
react-router-dom
源码
BrowserRouter
返回一个接收props.children的组件
Switch
利用Context
返回匹配到的第一个子节点 React.cloneElement
匹配方法
React.Children.forEach()
Route
根据window.location原理判断,接收传入的location
Context多层传递,再传一次Vue
渲染内容方式
三选一
children
function
children(props)
class
children
component
React.createElement(component,props)
render
render(props)
Link
返回一个a标签的组件
e.preventDefault()禁掉默认事件
history利用Context传值跳转
Redirect
利用Context
LifeCycle跳转组件
在初始化生命周期里直接跳转。history
Hooks类的方法
useHistory
函数
利用useContext方法>读取Context的history
useLocation
同上
useRouteMatch
同上
useParams
useRouterMatch.params||{}
路由守卫
封装一个包含router的组件,判断到底去哪儿,返回组件或重定向
DVA
建立model
在index注册
组件借助connect,这个是封装的react-redux里的connect
dva/dynamic
把组件用dynamic处理一下,让后页面引用时换成他就好
空节点
<>
React.Fragment
原理
虚拟DOM
JS对象
编程概念
虚拟的表现形式报错在内存中
通过ReactDOM等类库与真实DOM同步
这个协调的过程就是diff
最少更新
diff
深度度优先
复杂度
O(n)
type、key
遍历成本低
策略
真实DOM太庞大
比较成本太高
jsx
像写HTML一样的写js
开发效率
执行效率
类型安全
jsx为啥组件都要引入react
在babel转译的时候用到了React.creaceElement(...)
props
不能
key
ref
self
会被过滤掉无法传递下去
API
render
首次调用时,容器里的所有DOM元素都会被替换,后续会使用react的DOM的差分算法进行高效更新
diff
怎么判断是否首次
看看render的第二个参数是否有值
updateContainer
更新函数
源码
函数
参数
vnode 虚拟DOM节点
container 容器 真实要放到哪儿的节点
TODO
形成第一个fiber结构
fiber:fiber对象
大型项目组件树会很大,递归遍历成本很高,主线程被持续占用
任务分解
增量渲染
更新时能够暂停、终止、复用
给不同类型的更新赋予优先级
并发方面新的基础能力
更流畅。不卡顿
fiber对象属性
type
当前节点类型
props:属性
key:标记唯一
child:第一子节点
sibling:下一个兄弟节点
base:当前dom节点
return:指向父节点
node:真实的dom节点
源码
requestIdleCallback
浏览器的空闲时段内调用的函数排队
workLoop()
while判断
下一个任务(要执行的fiber)
空余时间
todo
performUnitOfWork(fiber) 执行更新当前的fiber
todo去添加fiber属性
原生标签
updateHostComponent(fiber)
node不是是真实DOM节点
createNode创建真实节点
createNode()方法
文本节点
document.createTextNode
创建文本节点
标签节点
document.createElement
创建元素
空标签<>
node= document.reateDocumentFragment()
updateNode(node, props)
添加节点属性
node是真实DOM节点
reconcileChildren()协调子节点
参数
fiber
fiber.props.children
todo
遍历children创建fiber链条
形成下一个新的fiber
第一个新的newFiber
原fiber添加child形成fiber.child=newFiber
新fiber添加sibling下一个兄弟节点
newFiber.sibling
newfiber.return指向原节点,也就是就是当前新fiber的父fiber
当有更新时存上base:老节点:只有文本节点没有子节点,否则其它都有子节点,而大多数都有平级的兄弟节点
组件
type.isReactComponent判断
函数组件
updateFunctionComponent
函数执行得到children
有hook时hook函数会执行
当有hook时存储当前节点到一个全局变量上
类组件
updateClassComponent
new Class
取出render
返回下一个要执行的fiber
有child返回child
没有child
while循环
返回当前fiber.sibling
返回当前节点父节点的兄弟节点 fiber.return.silbing
没有child返回sibling
没有sibling返回fiber.return
直到所有fiber都返回后停止
有下一个任务,没有空闲时间
没有下一个任务
commitRoot()执行提交
commitWorker(fiber)递归调用
由root节点开始依次把子节点兄弟节点appendChild插入到真实的父节点里
appendChild返回新添加的节点,也就是真实dom了
更新
删除节点
Component
传递props
createElement
源码
函数
参数
type
config
children
返回对象虚拟DOM
type
props
看源码流程
flow语法
packages
react-dom
src
client
ReactDOMLegacy
render()
legacyRenderSubtreeIntoContainer()
老节点
初次渲染
立即更新
updateContainer渲染更新
创建一个更新createUpdate()
enqueueUpdate()入队列形成链表
scheduleUpdateOnFiber处理更新
performSyncWorkOnRoot()
renderRootSync
workLoopSync()
performUnitOfWork()更新执行当前fiber,放回下次更新的fiber
beginWork
updateClassComponent
constructClassInstance初始化class组件实例
adoptClassInstance
classComponentUpdater
setState
异步
合成事件
在fiber上能监听到事件
同步
setTimeout和原生事件
监听不到事件,在组件更新时更新,就变成同步更新了
enqueueSetState
createUpdate()创建更新
scheduleUpdateOnFiber
子主题
挂着组件 mountClassInstance
执行生命周期
finishClassComponent
reconcileChildren协调
判断初次渲染还是更新
mountChildFibers
ChildReconciler(false)
reconcileChildFibers
newChild的数据类型
跟新数组情况
reconcileChildrenArray
与vue的不同
两头比较
react
基于fiber架构,单链表
mapRemainingChildren为方便取值生成了map图
数组一定要有key值原因,没有key就用了index
用老fiber生产map图,新fiber里在map图里找,有就复用,并且把map对应的那个删掉,以免下次对比
单个节点两两比较,不需要考虑位置的变化
reconcileChildFibers
commitRoot提交
commitRootImpl
循环渲染出来
执行完执行回调callback
刚看时像ts,但又不是ts,在入口里有注释
linux
hostname oyy
修改主机名
0 条评论
下一页