Rain120 / Web-Study

日常学习,工作写的笔记
66 stars 109 forks source link

Interview Prepare #16

Open Rain120 opened 2 years ago

Rain120 commented 2 years ago

三剑客

HTML

CSS

CSS3 Transitions, Transforms和Animation使用简介与应用展示

CSS GPU Animation: Doing It Right

JS

async defer

preload prefetch

在preload或prefetch的资源加载时,两者均存储在http cache。 当资源加载完成后,如果资源是可以被缓存的,那么其被存储在http cache中等待后续使用 如果资源不可被缓存,那么其在被使用前均存储在 memory cache。

  function _new() {
    const args = [...arguments];
    const obj = {};

    const _Constructor = args.shift();
    obj.__proto__ = _Constructor.prototype;
    const result = _Constructor.apply(obj, args);

    return result && typeof result === 'object' ? result : obj;
  }
  function call(context, ...args) {
    context = context ? Object(context) : window;
    const fn = Symbol('fn');

    context['fn'] = this;
    const result = context['fn'](...args);
    delete context['fn'];

    return result;
  }
  function apply(context, ...args) {
    context = context ? Object(context) : window;
    const fn = Symbol('fn');

    context['fn'] = this;
    const result = context['fn'](args);
    delete context['fn'];

    return result;
  }
  function bind(context, ...args) {
    let self = this;

   let fNop = function() {}

    function fBind() {
      return self.apply((this instanceof fBind? this : context), [...args, ...arguments]);
    }

    // new 的优先级大于 bind, 如果 bind 绑定后的函数被 new了, this 会指向当前函数的实例
    // 需要保留 原函数的原型链 上的属性和方法
    if (this.prototype) {
       fNop.prototype = this.prototype;
    }
    fBind.prototype = new fNop();

    return fBind;
  }
  // 创建新对象,指定其隐式原型为 Base
  var o1 = Object.create(Base);
  o1.__proto__ === Base; // true

  function create(prop, propertiesObject) {
    // 对输入进行检测
    if (typeof proto !== 'object' && typeof proto !== 'function' && proto !== null) {
        throw new Error(`Object prototype may only be an Object or null:${proto}`);
    }

    // 实现一个隐藏函数
    function F() {}

    // 函数的原型设置为参数传进来的原型
    F.prototype = prop;

    // 将属性赋值给该对象
    Object.defineProperties(F, propertiesObject);

    // 返回一个F函数的实例,即此实例的 __proto__ 指向为参数 proto
    return new F();
  }

BigInt

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/BigInt

其他

https://github.com/yygmind/blog/issues/43

Rain120 commented 2 years ago

Event Loop

Node

https://cnodejs.org/topic/5a9108d78d6e16e56bb80882

   ┌───────────────────────┐
┌─>│        timers         │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     I/O callbacks     │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     idle, prepare     │
│  └──────────┬────────────┘      ┌───────────────┐
│  ┌──────────┴────────────┐      │   incoming:   │
│  │         poll          │<─────┤  connections, │
│  └──────────┬────────────┘      │   data, etc.  │
│  ┌──────────┴────────────┐      └───────────────┘
│  │        check          │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
└──┤    close callbacks    │
   └───────────────────────┘
Rain120 commented 2 years ago

HTTP

https://halfrost.com/https-begin/

HTTP1.1

HTTP2

https://rain120.github.io/study-notes/engineering/http/version-compare

TLS 对称加密、非对称加密

http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html

TCP、UDP

TCP 传输控制协议

特性

  1. 可靠的,
  2. 面向连接需要三次握手
  3. 面向字节流的
  4. 只支持1对1
  5. 头部开销大,20-60个字节

拥塞控制

拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况。

拥塞流量控制

流量控制是作用于接收者的,它是控制发送者的发送速度从而使接收者来得及接收,防止分组丢失的。

https://zhuanlan.zhihu.com/p/37379780

UDP 用户数据协议

特性

  1. 面向无连接
  2. 不可靠的
  3. 面向报文的
  4. 支持 1对1,1对n,n对1,n对n
  5. 头部开销小,8字节,传输效率高

参考 https://coolshell.cn/articles/11564.html https://www.cnblogs.com/xiaolincoding/p/12732052.html 详细讲解TCP三次握手: https://www.eet-china.com/mp/a44399.html

GET vs POST

Rain120 commented 2 years ago

浏览器

浏览器缓存

本地缓存命中顺序,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-开头

Rain120 commented 2 years ago

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);
})

Rain120 commented 2 years ago

https://rain120.github.io/awesome-javascript-code-implementation/zh/design-pattern/#%E5%8F%82%E8%80%83

Rain120 commented 2 years ago

React

生命周期

https://rain120.github.io/study-notes/fe/react/lifecycle

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的优先级调度机制与事件系统 - 司徒正美的文章 - 知乎

Diff

https://zhuanlan.zhihu.com/p/20346379 React Virtual DOM Postmortem: https://jstutorial.medium.com/react-animated-tutorial-7a46fa3c2b96

Hook

// => 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

SSR(Server Site Render)

https://juejin.cn/post/6844904017487724557

Rain120 commented 2 years ago

v8

内存回收

图解 Google V8

https://time.geekbang.org/column/intro/100048001

image

Rain120 commented 2 years ago

前端安全策略

CSRF 跨站请求伪造(Cross-Site Request Forgery)

前端安全系列(二):如何防止CSRF攻击?

XSS

前端安全系列(一):如何防止XSS攻击?

Rain120 commented 2 years ago
Rain120 commented 2 years ago

Typescript

Rain120 commented 2 years ago

工程能力

性能监控

异常

https://www.zoo.team/article/catch-error

工程化

Webpack

Module Chunk Bundle的区别

Module:不同文件,都会被loader转换成一个模块的,不仅仅是ESM,Commonjs,AMD, etc... Chunk:在 Webpack 内部的打包进程中的代码模块;bundle由许多chunk组成,chunk有几种类型,入口entry,第三方 entry; Note: 当 Webpack 配置了 source-map 只有 一个 chunk对应多个 bundle

image

Bundle:构建完成后输出的的代码模块

module-chunk-bundle

hash chunkhash contenthash

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

Loader

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

定义 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
})
Rain120 commented 2 years ago

Mobx

原理

Proxy

Rain120 commented 2 years ago

技术能力体现

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/