Open Rain120 opened 2 years ago
https://cnodejs.org/topic/5a9108d78d6e16e56bb80882
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
https://halfrost.com/https-begin/
https://rain120.github.io/study-notes/engineering/http/version-compare
http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html
特性
拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况。
流量控制是作用于接收者的,它是控制发送者的发送速度从而使接收者来得及接收,防止分组丢失的。
在接收方窗口大小变为0的时候,发送方就不能再发送数据了。但是当接收方窗口恢复的时候发送方要怎么知道那?在这个时候TCP会启动一个零窗口(TCP Zero Window)定时探测器,向接收方询问窗口大小,当接收方窗口恢复的时候,就可以再次发送数据。
https://zhuanlan.zhihu.com/p/37379780
特性
参考 https://coolshell.cn/articles/11564.html https://www.cnblogs.com/xiaolincoding/p/12732052.html 详细讲解TCP三次握手: https://www.eet-china.com/mp/a44399.html
本地缓存命中顺序,Service Worker 缓存 => 内存缓存 => HTTP缓存(磁盘缓存) => HTTP/2 Push缓存
当浏览器要请求资源时
https://www.jianshu.com/p/54cc04190252
https://juejin.cn/post/6844903747357769742
https://calendar.perfplanet.com/2016/a-tale-of-four-caches/ https://web.dev/http-cache/
https://juejin.cn/post/6844903553795014663
https://juejin.cn/post/7039036362653171742
https://www.cnblogs.com/coco1s/p/5439619.html
CORS https://www.ruanyifeng.com/blog/2016/04/cors.html
简单请求
请求方法包括
请求头仅限于下面这些:
非简单请求
不是简单请求就是非简单请求
配置 与CORS请求相关的字段,都以Access-Control-开头
https://rain120.github.io/study-notes/fe/promise/implement
const STATUS = {
PENDING: 'PENDING',
FULFILLED: 'FULFILLED',
REJECTED: 'REJECTED',
}
class Promise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = null;
this.reason = null;
this.onResolvedList = [];
this.onRejectList = [];
const resolve = (value) => {
if (value instanceof Promise) {
return value.then(resolve, reject);
}
this.status = STATUS.FULFILLED;
this.value = value;
this.onResolvedList.forEach(cb => {
cb && cb();
});
}
const reject = (reason) => {
this.status = STATUS.REJECTED;
this.reason = reason;
this.onRejectList.forEach(cb => {
cb && cb();
});
}
try {
executor && executor(resolve, reject);
} catch (error) {
reject(error);
}
}
static resolve(value) {
return new Promise((resolve, reject) => {
resolve(value);
});
}
static reject(value) {
return new Promise((resolve, reject) => {
reject(value);
});
}
// 1. x === promise(它本身) => error
// 2. x => value => value
// 3. x 是 promise =>
// 3.1 => x.then =>
// 3.1.1 => function => value or error => resolve(value) or reject(error)
// 3.1.2 => value => value
resolvePromise(promise, x, resolve, reject) {
if (x === promise) {
return reject(new TypeError('Chaining cycle detected for promise #'));
}
let called;
const beCalled = called => {
if (called) {
return;
}
called = true;
}
if ((typeof x === 'object' && x !== null) || (typeof x === 'function')) {
const then = x.then;
try {
if (typeof then === 'function') {
then.call(
x,
y => {
beCalled(called);
resolvePromise(promise, y, resolve, reject);
},
e => {
beCalled(called);
reject(e);
}
);
} else {
resolve(x);
}
} catch (error) {
beCalled(called);
reject(error);
}
} else {
resolve(x);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ?
onFulfilled :
value => value;
onRejected = typeof onRejected === 'function' ?
onRejected :
error => {
throw error
};
const promise = new Promise((resolve, reject) => {
if (this.status === STATUS.FULFILLED) {
setTimeout(() => {
try {
const x = onFulfilled(this.value)
this.resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
});
}
if (this.status === STATUS.REJECTED) {
try {
setTimeout(() => {
try {
const x = onRejected(this.reason)
this.resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
});
} catch (error) {
reject(error);
}
}
if (this.status === STATUS.PENDING) {
try {
this.onResolvedList.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value)
this.resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
});
});
this.onRejectList.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason)
this.resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
});
});
} catch (error) {
reject(error);
}
}
});
return promise;
}
}
Promise.prototype.catch = cb => {
if (typeof cb !== 'function') {
return Promise.reject(new TypeError(`${cb} is not a function`));
}
return this.then(null, cb);
}
Promise.prototype.finally = cb => {
if (typeof cb !== 'function') {
return Promise.reject(new TypeError(`${cb} is not a function`));
}
return this.then(
value => Promise.resolve(cb()).then(() => value),
reason => Promise.resolve(cb()).then(() => {
throw reason;
}),
);
}
Promise.race = values => {
if (!Array.isArray(values)) {
const type = typeof values;
return new TypeError(`TypeError: ${type} ${values} is not iterable`)
}
return new Promise((resolve, reject) => {
for (let i = 0; i < values.length; i++) {
const value = values[i];
if (typeof value === 'function') {
x.then(() => resolve(value), reject);
} else {
resolve(value);
}
}
});
}
Promise.all = values => {
if (!Array.isArray(values)) {
const type = typeof values;
return new TypeError(`TypeError: ${type} ${values} is not iterable`)
}
return new Promise((resolve, reject) => {
const res = [];
const order = 0;
const processed = (value, i) => {
res[i] = value;
if (++order === values.length) {
resolve(res);
}
}
for (let i = 0; i < values.length; i++) {
const value = values[i];
if (typeof value === 'function') {
value.then(value => processed(value, i), reject);
} else {
processed(value, i);
}
}
});
}
// 中断
function wrapAbort(promise) {
let abort;
const abortPromise = new Promise((resolve, reject) => {
abort = reject;
});
let p = Promise.race([promise, abortPromise]);
return p;
}
function promisify(fn) {
return (...args) => {
return new Promise((resolve, reject) => {
fn(
...args,
(reason, value) => {
if (reason) {
reject(reason);
}
resolve(value);
}
);
})
}
}
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
const promise = new Promise((resolve, reject) => {
reject('失败');
}).then().then().then(data => {
console.log(data);
}, err => {
console.log('err', err);
})
https://rain120.github.io/study-notes/fe/react/lifecycle
Fiber是什么 https://juejin.cn/post/6844903975112671239 https://juejin.cn/post/6943896410987659277
Fiber如何挂起,恢复,终止
https://juejin.cn/post/6984949525928476703#heading-20
优先级 从高到底
// https://github.com/facebook/react/blob/caf6d470772d3bf06af5042502579477e367e04f/packages/scheduler/src/forks/Scheduler.js#L60
// Max 31 bit integer. The max integer size in V8 for 32-bit systems.
// Math.pow(2, 30) - 1
// 0b111111111111111111111111111111
var maxSigned31BitInt = 1073741823;
// Times out immediately
var IMMEDIATE_PRIORITY_TIMEOUT = -1;
// Eventually times out
var USER_BLOCKING_PRIORITY_TIMEOUT = 250;
var NORMAL_PRIORITY_TIMEOUT = 5000;
var LOW_PRIORITY_TIMEOUT = 10000;
// Never times out
var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt;
React Fiber的优先级调度机制与事件系统 - 司徒正美的文章 - 知乎
https://zhuanlan.zhihu.com/p/20346379 React Virtual DOM Postmortem: https://jstutorial.medium.com/react-animated-tutorial-7a46fa3c2b96
使用 https://rain120.github.io/study-notes/fe/react/hooks/base
函数式组件与类组件有何不同?
函数式组件捕获了渲染所用的值,通过闭包缓存到了上一次执行的值。(Function components capture the rendered values.) 类组件会在更新时,会更新整个 this 实例 https://overreacted.io/zh-hans/how-are-function-components-different-from-classes/
语法
调用方式
无法使用setState
useState VS setState
state = {
name: 'Rain120'
age: 20
}
setState({
age: 18
})
// => state = { name: 'Rain120', age: 18 }
const [, setProfile] = useState({ name: 'Rain120' age: 20 })
setProfile(prev => ({ ...prev, age: 18 }))
3. setState可以通过第二个函数得到最新的值,useState需要通过 useEffect
#### Suspense
工作原理:
- 在渲染方法中,从缓存中读取一个值。
- 如果该值已被缓存,则渲染继续正常进行
- 如果该值尚未缓存,则缓存抛出一个 promise
- 当 promise 解决时,React 会从中断的地方重试
```js
class Suspense extends React.Component {
state = {
promise: null
}
componentDidCatch(e) {
if (e instanceof Promise) {
this.setState({
promise: e
}, () => {
e.then(() => {
this.setState({
promise: null
})
})
})
}
}
render() {
const { fallback, children } = this.props;
const { promise } = this.state;
return <>
{ promise ? fallback : children }
</>
}
}
https://juejin.cn/post/6844903789959315470
React 性能优化 | 包括原理、技巧、Demo、工具使用
在SPA中
Hash 监听 hashchange
History
HTML5 中提供的 History API
<a href="..."></a>
, <link rel="prerender" href="..."/>
, <form method="GET" action="...">
持久型
非持久型(反射型 XSS)
DOM 型
HttpOnly
转义
CSP Content-Security-Policy(内容安全协议) https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP
type vs interface
相同点
- 都可以用来定义类型
- 都允许使用 extends 拓展类型
不同点
- type 可以声明基本类型别名, 联合类型, 元组等类型,interface不行
- interface可以类型合并,相同属性合并,类型变成never,type不行
any vs unknown
any是完全不检查,unknown 是 any 类型对应的安全类型,只能接受 unknown,any类型
https://www.zoo.team/article/catch-error
Module:不同文件,都会被loader转换成一个模块的,不仅仅是ESM,Commonjs,AMD, etc... Chunk:在 Webpack 内部的打包进程中的代码模块;bundle由许多chunk组成,chunk有几种类型,入口entry,第三方 entry; Note: 当 Webpack 配置了 source-map 只有 一个 chunk对应多个 bundle
Bundle:构建完成后输出的的代码模块
hash: 整个项目构建相关 chunkhash: 根据不同的入口文件(entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值 contenthash: 计算与文件内容本身相关
entry-option --> compile --> make --> build-bundle --> after-compile --> emit --> after-emit
1. entry-option:合并参数,默认 + 配置 + shell
2. compile: 创建实例 compiler,插件实例化,为webpack事件流挂上自定义hooks
3. make: 分析入口文件, 创建 compilation 对象
4. build-bundle:分析模块依赖,并处理依赖模块,使用loader处理
5. after-compile: 完成模块构建,编译完成
6. emit: compiler 输出模块,分为 入口模块(MainTemplate)和异步加载模块(ChunkTemplate),**最后可以修改 asset 的时机**
7. after-emit: 输出完成
https://rain120.github.io/study-notes/engineering/webpack/mini-webpack
https://mp.weixin.qq.com/s/SbJNbSVzSPSKBe2YStn2Zw
https://rain120.github.io/study-notes/engineering/webpack/webpack-optimize
https://rain120.github.io/study-notes/engineering/webpack/loader/base
定义: 模块转换器,实现非JS代码转换成Webpack能识别的代码。
pitch: loader上的一个函数,可阻断 loader 执行链。
Loader 生命周期
| ----> L1.pitch ----> L2.pitch ----> |
webpack | | file
| <---- L1 <---- L2 <---- |
定义 plugin是一个扩展器,它丰富了webpack本身,针对是loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,执行广泛的任务。
Compiler 整个 Webpack 配置的实例
Compilation 动态的资源集合,在某个编译阶段,产生的编译资源是不相同的。每个阶段都会有各自的Compilation
生命周期
compile --> compiltion --> make --> optimize --> after-compile --> emit --> after-emit
// 1
compiler.plugin('compile', function (params) {
// compile
});
// 2
compiler.plugin('compilation', function (compilation, params) {
// compilation
// 4
compilation.plugin('optimize', function () {
// optimize
});
});
// 3
compiler.plugin('make', function (compiler, callback) {
// make
callback();
});
// 5
compiler.plugin('after-compile', function (compilation) {
// after-compile
});
// 6
compiler.plugin('emit', function (compilation, callback) {
// emit
callback();
});
// 7
compiler.plugin('after-emit', function (compilation) {
// after-emit
})
Proxy
https://juejin.cn/post/6946210273061502990 https://www.mengfansheng.com/2020/01/01/%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%8C%96/
三剑客
HTML
CSS
Flex
BFC
选择器优先级
预处理器
CSS3 动画 在此之前所有的状态变化,都是即时完成
transition 转换
transform 变形
3D开启GPU加速
(transform: translateZ(0) or will-change: transform)
animation 动画
CSS3 Transitions, Transforms和Animation使用简介与应用展示
CSS GPU Animation: Doing It Right
JS
async defer
preload prefetch
preload特点
preload加载的资源是在浏览器渲染机制之前进行处理的,并且不会阻塞onload事件;
preload可以支持加载多种类型的资源,并且可以加载跨域资源;
preload加载的js脚本其加载和执行的过程是分离的。即preload会预加载 相应的脚本代码,待到需要时自行调用;
prefetch
原型链
继承
闭包
可以让你从内部函数访问外部函数作用域。
BigInt
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/BigInt
其他
https://github.com/yygmind/blog/issues/43