Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interview Prepare #16

Open
Rain120 opened this issue Feb 2, 2022 · 13 comments
Open

Interview Prepare #16

Rain120 opened this issue Feb 2, 2022 · 13 comments
Assignees

Comments

@Rain120
Copy link
Owner

Rain120 commented Feb 2, 2022

三剑客

HTML

CSS

  • Flex

    • 主轴 交叉轴
    • flex-shrink
    • justify-content
    • align-content
  • BFC

    • HTML
    • float 不为 none
    • position absolute, fixed
    • overflow 不为 visible
  • 选择器优先级

    • !important
    • inline 1000(256进制)
    • id 100
    • class 10
    • element 1
  • 预处理器

    • less
      1. mixin复用
      2. 递归书写
  • CSS3 动画
    在此之前所有的状态变化,都是即时完成

    • transition 转换

      缺点:

      • transition需要事件触发,所以没法在网页加载时自动发生
      • transition是一次性的,不能重复发生,除非一再触发
      • transition只能定义开始状态和结束状态,不能定义中间状态,也就是说只有两个状态
      • 一条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

  • async 并行下载,不确定执行顺序,执行阻塞解析,建议第三方的js使用,defer,并行下载,等HTML解析完了执行

preload prefetch

  • preload特点

    • preload加载的资源是在浏览器渲染机制之前进行处理的,并且不会阻塞onload事件;

    • preload可以支持加载多种类型的资源,并且可以加载跨域资源;

    • preload加载的js脚本其加载和执行的过程是分离的。即preload会预加载 相应的脚本代码,待到需要时自行调用;

  • prefetch

    • 一种利用浏览器的空闲时间加载页面将来可能用到的资源的一种机制;通常可以用于加载非首页的其他页面所需要的资源,以便加快后续页面的首屏速度;

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

  • new
  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;
  }
  • bind call apply
  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();
 }
  • 原型链

    • 类Person 实例person
      • person = new Person
      • Person.prototype === person.constructor
      • Person.prototype.__proto__ === Object.prototype
    • instanceof = (L, R) => L.__proto__ === R.prototype
  • 继承

    • 原型继承

      function Parent() {}
      
      function Child() {}
      
      Child.prototype = new Parent();
      // 多个实例原型共享问题
    • 组合继承

      function Parent() {}
      
      function Child() {
        Parent.call(this)
      }
      
      Child.prototype = new Parent();
      // 重复实例化 Parent
    • 寄生继承

      function Parent() {}
      
      function Child() {
        Parent.call(this)
      }
      
      Child.prototype = Object.create(Parent.prototype);
      Child.prototype.constructor = Child;
  • 闭包

    可以让你从内部函数访问外部函数作用域。

    1. 访问外部变量
    2. 设计成私有变量
    3. 缓存在内存中,无法GC

BigInt

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

其他

yygmind/blog#43

@Rain120
Copy link
Owner Author

Rain120 commented Feb 3, 2022

Event Loop

Node

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

  • timer(setTimeout, setInterval callback)
  • pending callbacks
  • idle prepare(内部使用)
  • poll(connections, data, etc.) 阻塞等待监听的事件来临,然后执行对应的callback
  • check(setImmediate callback)
  • close callback(socket.on('close', () => {}))
   ┌───────────────────────┐
┌─>│        timers         │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     I/O callbacks     │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     idle, prepare     │
│  └──────────┬────────────┘      ┌───────────────┐
│  ┌──────────┴────────────┐      │   incoming:   │
│  │         poll          │<─────┤  connections, │
│  └──────────┬────────────┘      │   data, etc.  │
│  ┌──────────┴────────────┐      └───────────────┘
│  │        check          │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
└──┤    close callbacks    │
   └───────────────────────┘

@Rain120
Copy link
Owner Author

Rain120 commented Feb 3, 2022

HTTP

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

HTTP1.1

  • 持久连接
  • TCP慢启动
    • 减少网络拥塞,由慢到快的过程
  • 队头拥塞
  • 多条TCP连接,竞争固定带宽

HTTP2

  • 多路服用
    • 使用一个TCP长连接,并发发送请求
  • header压缩
    • 缓存公有属性
  • 二进制格式
    • 二进制分帧层,将 header data分开发送
  • 服务器推送
    • 提前解析,推送需要的资源

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个字节

拥塞控制

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

  • 重传机制
    • 超时重传机制
      • 仅重传timeout的包
      • 重传timeout后所有的数据
    • 快速重传机制
      • 对超时包发送3次ACK

拥塞流量控制

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

  • TCP慢启动
  • 滑动窗口(Sliding Window)
    image
    • 数据分为
      • 已发送并且已经确认的包
      • 已发送但是没有确认的包
      • 未发送但是可以发送的包
      • 不允许被发送的包。
  • 零窗口(TCP Zero Window)

    在接收方窗口大小变为0的时候,发送方就不能再发送数据了。但是当接收方窗口恢复的时候发送方要怎么知道那?在这个时候TCP会启动一个零窗口(TCP Zero Window)定时探测器,向接收方询问窗口大小,当接收方窗口恢复的时候,就可以再次发送数据。

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

  • 区别
    • GET 具有幂等性,发送多少次都是一样的结果
    • 编码问题
    • 安全问题
    • GET 浏览器会把 header 和 data 一并发送出去,服务器响应 200(返回数据)
    • POST 浏览器先发送 Header,服务器响应 100 continue,浏览器再发送 data,服务器响应 200 ok(返回数据)
  • 误区
    • 作用: 其实没有所谓的限制,但是推荐,查询使用GET,提交使用POST
    • 参数传递: 都可以在链接和body传递,但是推荐,GET在链接上,POST放在Body
    • 参数长度: GET 2k,POST 无限制???其实这不对,HTTP本身不存在限制,是不同浏览器厂商的限制

@Rain120
Copy link
Owner Author

Rain120 commented Feb 3, 2022

浏览器

浏览器缓存

本地缓存命中顺序,Service Worker 缓存 => 内存缓存 => HTTP缓存(磁盘缓存) => HTTP/2 Push缓存

当浏览器要请求资源时

  • 调用 Service Worker 的 fetch 事件响应
  • 查看 memory cache
  • 查看 disk cache。这里又细分:
    • 如果有强制缓存且未失效,则使用强制缓存,不请求服务器。这时的状态码全部是 200
    • 如果有强制缓存但已失效,使用对比缓存,比较后确定 304 还是 200
  • 发送网络请求,等待网络响应
  • 把响应内容存入 disk cache (如果 HTTP 头信息配置可以存的话)
  • 把响应内容 的引用 存入 memory cache (无视 HTTP 头信息的配置)
  • 把响应内容存入 Service Worker 的 Cache Storage (如果 Service Worker 的脚本调用了 cache.put())

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

简单请求

请求方法包括

  • get
  • post
  • head

请求头仅限于下面这些:

  • content-type
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded
  • Content-Language
  • Accept
  • Accept-Language
  • Last-Event-ID

非简单请求

不是简单请求就是非简单请求

配置
与CORS请求相关的字段,都以Access-Control-开头

  • Access-Control-Allow-Origin
    表示接受什么域名的请求
  • Access-Control-Allow-Credentials
    表示是否允许发送Cookie,默认情况下,Cookie不包括在CORS请求之中。若服务端配置为 true, 客户端必须在AJAX请求中打开withCredentials属性。
  • Access-Control-Expose-Headers

@Rain120
Copy link
Owner Author

Rain120 commented Feb 3, 2022

  • Promise

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 #<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
Copy link
Owner Author

Rain120 commented Feb 3, 2022

@Rain120
Copy link
Owner Author

Rain120 commented Feb 3, 2022

React

生命周期

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

Fiber

https://juejin.cn/post/6984949525928476703#heading-20

  • 任务分类

优先级 从高到底

  • No Priority,初始化、重置 root、占位用;
  • Immediate Priority(-1),这个优先级的任务会立即同步执行, 且不能中断,用来执行过期任务;
  • UserBlocking Priority(250ms), 会阻塞渲染的优先级,用户交互的结果, 需要及时得到反馈
  • Normal Priority(5s), 默认和普通的优先级,应对哪些不需要立即感受到的任务,例如网络请求
  • Low Priority (10s), 低优先级,这些任务可以放后,但是最终应该得到执行. 例如分析通知
  • Idle Priority(没有超时时间),空闲优先级,用户不在意、一些没必要的任务 (e.g. 比如隐藏的内容), 可能会被饿死;
// 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

  • tree diff
    • 比对父节点的变化
    • 跨层级变更,直接创建新节点,然后删除旧节点
  • component diff
    • 同类型,比较virtual dom树
      • React 允许用户通过 shouldComponentUpdate() 来判断该组件是否需要进行 diff
    • 不同类型,直接标记dirty component,替换所有子节点
      • 结构相似也会重新创建
  • element diff
    • INSERT_MARKUP(插入)
    • MOVE_EXISTING(移动)
    • REMOVE_NODE(删除)

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

Hook

函数式组件捕获了渲染所用的值,通过闭包缓存到了上一次执行的值。(Function components capture the rendered values.)
类组件会在更新时,会更新整个 this 实例
https://overreacted.io/zh-hans/how-are-function-components-different-from-classes/

  • 语法

    • class 需要继承Component,然后 render 返回组件
    • function直接返回
  • 调用方式

  • 无法使用setState

  • useState VS setState

  1. setState({}) / setState({}, () => {}) / setState((state, props) => {}, () => {}); useState只能在函数中使用
  2. setState会合并参数,useState不会
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
}))
  1. setState可以通过第二个函数得到最新的值,useState需要通过 useEffect

Suspense

工作原理:

  • 在渲染方法中,从缓存中读取一个值。
  • 如果该值已被缓存,则渲染继续正常进行
  • 如果该值尚未缓存,则缓存抛出一个 promise
  • 当 promise 解决时,React 会从中断的地方重试
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

优化

  • PureComponent(浅对比 props, state), React.memo(浅对比 props)
  • shouldComponentUpdate
  • useMemo, useCallback 实现稳定的 Prop
  • 状态下放,缩小影响范围
  • Key对比
  • 避免在 didMount、didUpdate 中更新组件 State
    • didMount、didUpdate在render之后,如果再次修改值,则会再一次render
  • 组件按需挂载
    • 懒加载
      • 滚动加载
      • 虚拟列表
  • debounce、throttle

React 性能优化 | 包括原理、技巧、Demo、工具使用

路由

在SPA中

  • SPA 无法记住用户的操作记录,无论是刷新、前进还是后退,都无法展示用户真实的期望内容。
  • SPA 中虽然由于业务的不同会有多种页面展示形式,但只有一个 url,对 SEO 不友好,不方便搜索引擎进行收录。

「前端进阶」彻底弄懂前端路由

Hash
监听 hashchange

  • 兼容性好
  • 无需服务端配置

History

HTML5 中提供的 History API

  • pushState保留着历史记录

SSR(Server Site Render)

https://juejin.cn/post/6844904017487724557

@Rain120
Copy link
Owner Author

Rain120 commented Feb 3, 2022

@Rain120
Copy link
Owner Author

Rain120 commented Feb 3, 2022

前端安全策略

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

  • 验证 HTTP Header Referer
  • 验证码
  • SameSite 用来防止 CSRF 攻击和用户追踪 https://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html
    • strict 完全禁止第三方 Cookie
    • lax 允许这几类发送Cookie <a href="..."></a>, <link rel="prerender" href="..."/>, <form method="GET" action="...">
    • none 选择显式关闭SameSite属性,将其设为None。不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。
  • 添加 token 验证

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

XSS

  • 持久型

    • 常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。
  • 非持久型(反射型 XSS)

    • 常见于通过 URL 传递参数的功能,如网站搜索、跳转等
  • DOM 型

    • DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。
  • HttpOnly

  • 转义

  • CSP Content-Security-Policy(内容安全协议) https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP

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

@Rain120
Copy link
Owner Author

Rain120 commented Feb 3, 2022

  • 数据结构
    • 排序
    • 链表
    • 反转链表

@Rain120
Copy link
Owner Author

Rain120 commented Feb 3, 2022

Typescript

  • type vs interface

    相同点

    1. 都可以用来定义类型
    2. 都允许使用 extends 拓展类型

    不同点

    1. type 可以声明基本类型别名, 联合类型, 元组等类型,interface不行
    2. interface可以类型合并,相同属性合并,类型变成never,type不行
  • any vs unknown

    any是完全不检查,unknown 是 any 类型对应的安全类型,只能接受 unknown,any类型

@Rain120
Copy link
Owner Author

Rain120 commented Feb 3, 2022

工程能力

性能监控

异常

  • 异常分类
    • Error
    • ReferenceError
    • SyntaxError
    • TypeError
    • 其他
  • 异常捕获
    • window.onerror()
    • event: onerror, addEventListener('error', cb);
    • Promise => addEventListener("unhandledrejection")
    • React
      • error boundaries
        • componentDidCatch(error, info) {}
        • error boundaries 并不会捕捉下面这些错误:
          • 事件处理器;
          • 异步代码;
          • 服务端的渲染代码;
          • 在 error boundaries 区域内的错误
  • 异常上报
    • Sentry
    • trace
      • 内部自研
      • zipkin + jaeger

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
Copy link
Owner Author

Rain120 commented Feb 19, 2022

Mobx

原理

Proxy

@Rain120
Copy link
Owner Author

Rain120 commented Feb 19, 2022

技术能力体现

  • 组件化能力
  • 工程化能力
  • 调研、并尝试一些demo
    • 输出文档
    • 咨询其他有经验的同学
  • 指导、协助其他同学解决问题
    • 提升技术全面性,和沟通能力,问题解决能力
    • 传递自己的一些思想,并与之探讨
    • 提升初级同学的知识面,了解其他人对于这个问题的思考

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/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant