掘金开篇:面试与感想

797 阅读13分钟

前言

内容包括面试考点,答题技巧,以及一点工作后的经历... 读者可以根据右侧导航目录,按需阅读,希望各位都有所获。

您的简历,与岗位要求不符

开篇不想暴击,但很有必要。往往我们为了面试,准备了很久,投了心仪的厂子,结果等来的不是面试通知,而是一封冰冷的邮件... 您的简历,与岗位要求不符

一般这种情况可以总结为几类,评论欢迎补充:

    1. 您是真滴菜,掰掰。
    1. 年龄太大,水平一般,我们要的是新鲜血液,掰掰。
    1. 学历太低,掰掰(厂子的要求越来越高了)。
    1. 内容太多,没有重点和主次,看不到实质内容,掰掰。

重要分析一下第 4 点,可以解读出很多东西:

    1. 内容太多,可能你写了满满一页,全是没营养的东西。建议:将亮点罗列出来。
    1. 可能你前后端都擅长,所以写了很多后端的内容,没有分清主次,我们招的是前端。
    1. 内容太多,但看不到真实的东西,比如你写的代码,我觉得你在吹牛。需知:「Talk is cheap. Show me the code」,建议:简历里带上你的 github、掘金等链接,若没有?还不赶紧动起来!
    1. ...待补充

引导面试官

简历上面写了什么,决定了面试官会问你什么。如果你写的很泛,除非你真的很全面无敌,否则情况会很糟。

面试是有技巧的,简单的一问一答太过死板,试着在回答的时候引申向你擅长的领域,抛出一个个关键词诱导考官提问。

具体的例子,下文会涉及。但在此之前,我们需要做足功课,务实基础。此外,请务必准备一些杀手锏,在需要的时候亮瞎考官的……,比如 HTTPS 所有加密算法chromium 进程 IPC 原理斐波拉契第 n 数的 logn 解法浏览器渲染过程Vue 编译器架构快排以及手写 V8 排序

数据结构和算法系统练习

算法是大厂必考的项目,这里笔者提供 leetcode 字节跳动的企业题库,后面会慢慢补齐其他厂的。

高频基础

进入正题,前端要往深了走,基础很重要。

闭包

定义:有权访问另一个函数作用域中的变量的函数。

产生原因:先解释下作用域链,然后说明当前环境存在指向父级作用域的引用。

应用:定时器 / 事件监听 / ajax / Web Worker 等都有涉及,关键就是使用了回调函数……

面试时可以展开的点,可以引出下一个话题:闭包变量存在堆中一个名为 [[scope]] 的对象内,同时闭包也常以 高阶函数 的形式创建,V8 的 垃圾回收 机制也涉及到了闭包。

堆栈及 V8 垃圾回收

讲到闭包,就会涉及到内存存储空间的知识,进而可以引申到垃圾回收机制 GC。

我们知道:栈中保存变量,函数调用完,栈顶空间自动销毁,然后切换执行上下文,假如存储对象很大,切换的开销自然也变得巨大。于是,堆就出场了。

强调:V8 的 GC 作用的是堆而不是栈。
  • V8 设置堆内存上限为 1.4G,原因:js 是单线程执行,堆内存在进行 非增量 垃圾回收时需耗时 1 秒之久,这期间会导致 js 暂停、应用卡顿,造成性能下降,显然,1.4G 是经过深思熟虑的。
  • 新生代临时内存上限 32M:涉及 Scavenge 算法,分正在使用的 from 空间,闲置的 to 空间。
  • Scavenge 缺点:浪费一半空间,用在大空间复制效率极低,所以老生代换了算法。
  • 老生代常驻内存:涉及 变量晋升,两个算法 mark-sweep 标记清除mark-compact 标记整理。还有 增量标记算法,这个算法优化将 GC 期间造成的 js 阻塞减少到原本的 1/6。
  • 垃圾回收是在 Event Loop微任务阶段进行。

GC 还可以展开的点:增量清理、增量整理、多核并行清理,内存泄漏,WeakMap、WeakSet 弱引用。

原型

回答时,可以按照以下顺序来回答。

    1. 原型对象概念:函数都会自带 prototype 属性 (箭头函数除外),该属性指向原型对象。
    1. 构造函数概念:new + 函数执行 = 构造函数,并返回实例对象。let obj = new Fn()
    1. 实例对象有个 __proto__ 属性,全名 [double underscore proto] 读作 dunder proto 即可。该属性指向构造函数的原型对象。
    1. 原型链概念:__proto__ 指向父类对象,接着不断追溯父类原型对象,直到指向 Object 对象为止,再上面只剩 null 了。明白了原型链,那么手写 instanceof 就不在话下了。
    1. 原型继承,继承的优点和缺点,比继承更佳的方案:组合模式

列出几个常用的方法:

  • Object.getPrototypeOf(obj) // 获取原型对象,比如 instanceof 源代码

  • Object.setPrototypeOf(subClass, superClass) // 继承父类的静态方法

  • Object.prototype.hasOwnProperty(attr) // 检查对象自身是否有该属性

  • in // 检查对象或原型对象中是否有该属性 if (k in O) {}

  • Object.create(proto, [propertiesObject]) // 一个不带任何原型链属性、纯净且高度可定制的对象,比如数据字典可以用 create(null) 代替 {} 初始化

Event Loop

这块算是面试的重头戏了,资料太多,照搬没有意思,认清注意下面几个点。

  • 宏任务包括普通队列和延迟队列,宏任务内还维护一个微任务队列。
  • 微任务前有个 nodejs 的 process.nextTick
  • 微任务末尾有一个 requestAnimationFrame,接着是 UI 渲染,Web Worker,注意这几个的顺序。
  • 了解微任务的位置为什么在宏任务的末尾。
  • Nodejs 的 Event Loop:注意 pending callbacks 挂起的系统操作回调,比如 tcp 错误的连接请求。
  • Nodejs 的 setTimeout 小于 4ms 一律以 4ms 处理。
  • process.nextTick:是独立于 Event Loop 的任务队列,且在微任务之前执行。
  • 区别:Nodejs 微任务在每个阶段之间,且微任务队列具有最高优先级,注意特殊的 nextTick。

花点时间详细了解 Event Loop 里面的细节是很有必要的,毕竟主流前端框架中的批量更新,fiber 的调度,事务等都或多或少与之相关,在提高性能这一块 Event Loop 可以做的事情很多。

Promise

  • 返回 promise 能解决回调地狱,错误冒泡将错误一次 catch。
  • function* 为生成器函数,实现机制为协程,可以做到代码可控,不需要切换上下文。
  • async / await 利用协程和 Promise 实现了同步方式编写异步代码的效果。
  • 异步可控遍历:for...of + await 更优于 forEach + await 的地方是使用了迭代器 array[Symbol.iterator]().next() 的语法糖,forEach + await 别用就对了。
  • 高频面试题:手写 Promise 的各种方法。

常见的设计模式

设计模式并不是多么晦涩难懂的概念,我们日常开发中多少都会接触到。它是前人在实际生产项目中不断迭代、试错、修正、抽象而来的经验总结,使用设计模式可以让你的代码变得更加可维护、易于扩展。说人话就是平常能用就用,重构时必用。

  • 工厂模式:组件化中常用的重构利器。

  • 单例模式:分懒汉式和饿汉式,比如数据库连接,vuex、redux 等状态管理工具,甚至更复杂的场景,必须掌握。

  • 观察者模式:太多地方用了,比如 Vue 响应式中的收集依赖和触发更新。

  • 发布-订阅模式观察者模式 的区别:在观察者模式中,观察者是知道 目标 Subject 的,Subject 一直保持对观察者进行记录。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有通过一个中间层,消息代理进行通信,同时是异步的。在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。

  • 观察者模式 举例:你对某知名企业很感兴趣(你作为观察者知道企业大名),投递简历后企业维护你和其他面试者的简历(企业知道了你),当职位空缺时主动通知你和其他面试者。这个例子,双方是直接的关系。

  • 其实还有:状态模式策略模式 都比较常见,也比较简单,一看就会,实际开发中如果写烦了 if-else ,也可以换换写法,优雅一下。

  • 享元模式中介者模式,emmm...跟 发布-订阅模式 极其的类似。

  • 适配器模式(用于封装)、装饰者模式(用于增强功能)、代理模式(Vue3 的 Proxy)较易混淆,有兴趣就多了解。

主流框架

主要讲讲主流框架 VueReact,包括但不限于:框架演进、框架横向对比、虚拟 Dom、渲染、响应原理、版本差异、Diff 算法等...

V8 执行 Js 的过程(即时编译 JIT)

  • 1.解释器 通过词法分析和语法分析将源码转成 AST,根据 AST 生成执行上下文。
  • 2.解释器 根据 AST 生成 V8 字节码。为什么不是二进制机器码:机器码太大,执行占用太多内存。
  • 3.解释器 逐行执行字节码,遇到热点代码启动 编译器 进行编译,生成对应的机器码, 以优化执行效率。

针对 Js 运行的性能优化:

  • 1.提升单次脚本的执行速度,避免 Js 的长任务霸占主线程,这样可以使得页面快速响应交互;
  • 2.避免大的内联脚本,因为在解析 HTML 的过程中,解析和编译也会占用主线程;
  • 3.减少 Js 文件的容量,因为更小的文件会提升下载速度,并且占用更低的内存。
科普:很多人在刚入门的时候对 V8、Webkit、JSCore、runtime 这几个词没有概念,或者傻傻分不清,笔者在这里简单梳理下。
  • Js 是动态解释型语言:在运行时通过解释器进行动态解释和执行。
  • 编译器:能生成二进制文件。
  • 即时编译 JIT:一种热门的字节码配合解释器和编译器的技术。
  • 比如 go 是静态编译的语言,可在不同平台交叉编译;java 也是,附带动态特性,有一层 jvm,可以跨平台直接运行。
  • 静态编译:不依赖动态链接库,可以任意部署到各种运行环境,就是体积大一点。
  • V8(Chrome 基于 JSCore 的升级版,性能更佳) / JSCore(起源于 Safari,是 WebKit 的默认 JS 引擎,手机端都是使用的 JSCore) 执行在 WebView 的 WebKit 渲染引擎中。
  • JavaScript Runtime 用来执行JavaScript代码用的,为其提供了一个运行时环境,提供解释/编译、自动内存管理(GC)、对象模型、核心库等功能。
  • V8 将 runtime 看成高级语言虚拟机,GC 等都在里面
  • WebKit 和 V8 引擎都在渲染进程中。

AST

AST,似乎到处都有它的影子,包括浏览器、主流框架、Webpack 等打包工具、Babel、跨平台应用框架,如 uni-app 、Vue 转小程序。了解了 AST,之后不论是优化还是转换,不过是增删改查罢了。

Vue 的 template 编译,渲染机制

  1. 解析模版,生成 AST 语法树:

    词法分析:使用大量的正则表达式对模板进行解析,遇到标签、文本的时候都会执行对应的钩子进行相关处理。

    优化:其中涉及 静态节点优化,设置 static 属性用于 Diff 时剪枝,静态节点就是一些不带变量的文本节点,或者一些不带 if 和 for 的节点。用于在下次渲染时直接跳过。

    深度遍历 AST,标记静态节点以优化跳过比对,最后转为可执行的代码。

    总结:语法分析 -> 语法分析 -> 优化

  2. 到这里,其实 AST 的任务已经结束。以下是 template 接下来的代码逻辑。

    AST 会经过 generate 函数得到 render 函数,不同的节点有不同的 render 处理方式。render 生成虚拟 Dom,最后 patching,Diff,渲染 Dom。

3.引申:flutter、React Native 的渲染机制

Vue 的响应原理,忽略细节版

vue2.0 响应式原理 看这篇够够的了。

  • view 变化触发 data 更新通过事件监听

  • 以下是 data 触发 view 更新

  • v2 中是递归遍历 data 中的所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter,在getter 中做数据依赖收集处理,在 setter 中 监听数据的变化,并通知订阅当前数据的地方

  • 具体:

  • 1.实现一个监听器 Observer:对数据对象进行遍历,包括子属性对象的属性,利用 Object.defineProperty() 对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。

  • 2.实现一个解析器 Compile:解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,调用更新函数进行数据更新。

  • 3.实现一个订阅者 Watcher:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。

  • 4.实现一个订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。

  • 限制:

  • 无法检测对象属性的添加与删除,需要配合 set/delete

  • defineProperty 监听 array 是有缺陷的:改变 length 长度或者超出设置,监听都会失效。

  • 性能问题,层级太深导致性能下降

  • 所以 vue 在数组的原型方法上做了一些手脚 defineProperty(obj, 'push') 监听 push 方法

  • 检测数组变化源码解析:

  • 1.Object.create(arrayPrototype) 初始化一个以数组原型对象 Array.prototype 为参数的对象:Object.create(Array.prototype)

  • 2.将该对象里的所有数组方法用 definePrototype 重写

  • 3.在数据 observer 绑定的时候,判断数据对象是否有 __proto__,有就将数据直接绑定上重写后的原型

  • 4.如果浏览器不支持 __proto__,依据原型链,就将重写的原型直接挂在数据上好了。

  • 5.这样当调用数组 api 时,可以通知依赖更新,如果数组包含引用类型,继续递归遍历监控

  • $set 原理:

  • 如果目标是数组,直接使用数组的 splice 方法触发相应式。

  • 如果目标是对象,会先判读属性是否存在、对象是否是响应式。

  • 最终如果要对属性进行响应式处理,则是通过调用 defineReactive 方法进行响应式处理,最后通知订阅 notify。

  • 总结:对象和数组都是通过递归遍历

Vue2 Diff

vnode 对象是树的递归遍历

  • O(n^3) -> O(n)
  • O(n^3) 计算:单个节点与旧 vnode 的依次比较,为 n^2,计算差异后遍历找到位置进行删除或增加,为 n,最终为 n^3
  • diff 的必要性,算法优化能够同时减少回流和重绘,具体触发流程:触发setter -> 触发通知 notify -> 触发 watcher 加进异步更新队列,eventloop 会清空队列,watcher 尝试执行更新函数 -> 调用渲染函数,重新计算 vdom -> 进行 diff

代码逻辑:

  • 没有旧节点,直接创建新的。

  • 新旧 vnode 不同,直接销毁旧的,创建新的。

  • 新旧 vnode 相同,继续比较子节点:

    其中 vnode 为文本节点,与旧不同则直接更新

    子节点依旧是新旧之间的比较,只有新节点直接创建,只有旧节点则删除旧的,新旧又不同,开始 diff 核心算法,重点讲解:

    1. while 循环比较新旧子节点:头索引跟头比较,尾跟尾,比完缩减往中间收拢,比较遵从:

    2. 头与头比较,相同则复用不作处理,同时头++,尾、头尾、尾头的目的都是为了复用

    3. 用 key 比较

    4. map 表遍历查找

    5. 剩余节点,批量新增或删除

总结:能不动就不动,不行就移动,最后处理新建或者删除。相比React的Diff算法,同样情况下可以减少移动节点次数,减少不必要的性能损耗,更加的优雅。

Vue3 Diff 优化:

  • vdom:创建 vdom 的时候多了个 dynamicChildren 动态节点,patch 的时候只比对动态。

    vue2 静态节点也会 patch。

  • vdom:节点变更类型用 patchFlag 细分,用位掩码组合,作为判定更新的依据。

    vue2 如果是普通节点,会通过内置的update钩子全量进行新旧对比,然后更新;如果是component,则会在prepatch阶段进行判断,有变化则会重新触发forceUpdate,造成很多无用的重复对比。

  • diff 核心变化:用数组 map 记录节点变更的位置以及新增的节点 + 最长子序列(如果递增则位置不变)。

  • 相同事件缓存不会重新生成。

React16 Diff

vnode 对象是链表的循环遍历,与递归不同的是可以设置暂停和恢复,根据调度展开的优化代码。

  • 复用没有变更的节点,用 key。

  • 先比较两棵树的根节点,若是不同的类型,则直接销毁旧的,重建新的。若是相同的类型,则看下 className、style 等是否相同,同时保留不变的状态,比较完继续对子节点递归,比如列表,在设置 key 的情况下 diff 的开销会更小 (没有key的情况下,在表头插入将会重建,表尾只会添加)

Vue3 新特性

  1. v3 重写了 vdom,性能提高 12 倍,ssr 提高 23 倍。
  2. v3 支持 tree-shaking,原理 ?
  3. babel 编译的代码经过 uglifyjs 的 tree-shaking 因为函数副作用(IIFE、原型属性等影响)的原因无法真正消除所有无用的代码,而 rollup 却可以,因为它们做了程序流分析。另外静态 import 有利于 t-shaking。
  4. v3 Composition API 类似于 React Hooks:优势按着逻辑编程。
  5. v3 对象式的组件声明方式,可以更好的 TS 支持,自定义渲染器 vugel。
  6. v2 的 definePropterty() 实现的数据绑定无法实现数据对象新增属性值的变化,且vue中的数组方法也是自己 polyfill实现的。
  7. 作用域插槽改成了函数的方式,这样只会影响子组件的重新渲染,提高了性能。
  8. 监测机制改进了 defineProperty 的不足,另外支持 Map、Set、WeakMap 和 WeakSet。

MVC,MVVM 架构演变

MVC 相信这是绝大部分程序员最早接触到的架构。

MVVM 双向绑定:V 的变动,自动反映在 VM 上。V 和 M 不发生联系,其他部分的通信都是双向的。

MVVM 框架目前存在的问题:执行效率,数据改变, UI 也会频繁更新,引发子组件更新,性能不是最优。好消息是 Vue 3 已经解决了这个子组件重复渲染的问题,但需知没有完美的解决方案,只有舍与得。

很多人没有分清的是:ReactJs 其实是一个单向数据流的 js 库,状态驱动视图,是 MVC。而 React 全家桶是 MVP,近似 MVVM。

本身 C,P,VM 的边界界定就十分模糊,不用钻牛角尖,核心其实就是每一层专注于每一层的任务。如何对代码进行组织管理,还是要看需求来界定的,这也是框架架构模式不断发展的原因。

Vue 和 React 的区别

这一道题,可以说是上面的归总,我们可以从大到小,从略到详,从思想、生态、语法、数据、通信、Diff、版本等角度来讲,笔者整理了一些,以下挑几个重点吧...

Vue 和 React

  • 生态:以 2020 年国内情况来看,可以说不分伯仲了,再看 Vue3 released on Friday, September 18, 2020,您品,您细品。
  • 上手难度:显然 Vue 更易上手,Vue 的理念就是约束你、成就你。
  • 架构:Vue 是 MVVM,双向绑定,依赖自动跟踪;Reactjs 是 MVC,单向数据驱动。Vue 的 v-model 本质上是 input 事件和 value 的语法糖,可以使用 props/event 自定义;React 的 setState 伪异步,更新渲染需要手动优化。
  • 渲染:Vue、React 的 Diff 区别,前者是树的递归遍历、后者链表。
  • ...

Vue3 和 React16 的区别

  • Vue3 setup(props) 在 beforeCreate 之前
  • Vue3 setup(props) props 不能解构,形如 setup({name}) 这样是错误的,会造成 watch 无法更新响应
  • React16 hook 函数最顶层使用,保证顺序
  • Vue3 组件选项 setup 声明周期内只被调用一次,取名就能看出来,初始化并收集依赖,数据更新就会执行依赖
  • React16 hook 实际每次渲染还是执行整个函数,本质上编译方法还是 React.createElement,按顺序存储 fiber 链表,每次渲染都是按顺序取节点,所以禁止条件调用;
  • React16 每次渲染,useEffect 都会重新执行并产生闭包,性能和 GC 压力上逊于 v
  • React16 监听数据时,useEffect 的第二项 [] deps 会进行前后两次渲染的浅对比 Object.is
  • React16 hook 闭包陷阱:假如忘记传递正确的依赖项数组,useEffect、useMemo 可能会捕获过时的变量
  • Vue3 setup(props) computed watchEffect 自动跟踪依赖
  • 响应原理差异
  • ...

Vue3 和 React16 的相似处

  • Suspense:Vue3 的 Suspense 异步嵌套比 React16 更加轻量,React16 还在完善中
  • 自定义 hook:逻辑重用,不用反复横跳,返回的值自定义不用担心命名冲突……
  • 创建响应式数据:Vue3 的 ref,React16 的 useState
  • ...

Vue3 和 React16 总结

  • React16 本身富有创造力,我们需要自己设计顺序、渲染优化
  • Vue3 的 hook 灵感来源于 React16,同时响应式模式恰好解决了 React16 的问题:hook api 执行顺序、优化、追踪、闭包
  • 谈谈 Vue3 抄袭:Vue3 相比 React16 有相似之处,更有超越的地方。框架本身就是给人用的,易上手也是其中重要的前提。react-router 也有借鉴 vue-router……
  • ...

浏览器与网络协议

从输入到渲染的整个流程? 流程里每个部分拿出来都能深挖,我认为这道题颇有道中三生万物的韵味,前端的一切都可以从这里开始,说白了 PC 的前端是被绑定在浏览器中的。

我本人原本对于渲染的这一块,图层和合成理解并不清晰,于是将这篇放这里:为什么 CSS 动画比 JS 高效

最新性能指标

  • LCP 实时更新的最大内容绘制:2.5s 内算体验优秀,一直更新直到用户交互后停止记录,大元素的快速载入总是让人感觉网速良好。
  • FID 首次输入延迟:即首次交互响应时间,记录在 FCP 和 TTI 之间用户首次与页面交互时响应的延迟,小于 100ms 为佳。补充:因为 idle 内假如有超过 50ms 的长任务,待页面响应会给人一种延迟感,综合考虑为 100ms。
  • CLS (Cumulative Layout Shift) 累计位移偏移:记录了页面上非预期的位移波动,位移距离 × 位移影响的面积 < 0.1 满足这个公式便算体验优秀,反例:小屏手机上突然插入 dom 或广告让人膈应。

浏览器缓存

掌握强缓存字段,协商缓存字段。

展开:除了常规的缓存手段,还可以扩展下 1.代理缓存,2.V8 代码缓存

HTTP

这一块的内容是通过一些书籍和文章整理来的,记录了一些容易混淆的点。

首先需要理清:http2 解决性能问题;http3 解决 http2 遗留问题;https 解决安全问题。

HTTP 加密算法

  1. 对称加密

  2. 非对称加密

  3. 传统 RSA 握手:是 1. + 2. + 数字证书 结合(在交换密钥环节使用公开密钥加密方式,建立通信交换报文阶段使用共享密钥加密方式)

  4. TLS1.2 握手,与 3. 的区别在于 pre_random 的生成方式不同。

  5. 证书相关:

    证书只解决了公钥持有人到底是谁。

    原证书内容:签发者、证书用途和基本信息、服务器公钥、服务器加密算法、服务器 HASH 算法、证书的到期时间等。

    原证书内容 + 最重要的防篡改的数字签名 = 服务器发给客户端的数字证书

    数字签名:对原证书内容进行 hash 函数(比如 SHA256)生成的摘要 digest(摘要代表服务器身份,可以理解为身份证),经过 CA 私钥加密后生成数字签名 signature,将数字签名附在原证书末尾。这里跟 JWT 很像。

  6. 客户端收到数字证书,使用 CA 公钥解密 signature 得到 digest 验明身份,再使用 hash 函数对证书原数据计算,得到的结果与 digest 对比,完全一致说明数据未被修改

  7. 放出《图解 HTTP》原文用以确认:

    服务器有自己的公钥和私钥,此时向 CA 申请证书,提交自己的公钥及基本身份信息。

    CA 也有自己的公钥和私钥,...用 CA 自己的私钥...生成数字签名,同时将服务器公钥绑定入证书。这里注意:CA 公钥已经在我们安装浏览器的时候植入我们机器了。

    客户端收到数字证书,先用浏览器内置的 CA 公钥解密证书的数字签名,得到 hash 后的摘要,我们假定叫做 hash_0,然后我们自己使用 hash 函数对证书内原报文进行计算,生成 hash_1,两者一致即可确认服务器公钥的真实性。

  8. Q:中间人是否会拦截发送假证书到客户端呢?

    A:因为证书的签名是由服务器端网址等信息生成的,并且通过第三方机构的私钥加密中间人无法篡改; 所以最关键的问题是证书签名的真伪。

  9. 还有 网络安全4 种常见连接方式TCP 握手和挥手TCP 流量控制和拥塞控制HTTP 传输各种资源的表头字段流与分段传输 (包括上传和下载)TCP 序列号 等一堆重点。

  10. 扩展:

    UDP 协议在游戏场景使用较多,有 DTSL 保证安全,UDP 相当于 4 层的 IP 协议,方便上层协议的自定义和扩展。

    https 握手证书验证过程太耗费流量,同时因安全问题被禁止压缩,且假如把 tls 只是看成一个技术参考,是可以任意修改的,于是很多企业开始自定义内部协议,比如微信。

    QUIC(Quick UDP Internet Connections) 基于UDP的传输层协议,提供像TCP一样的可靠性。

    直播协议:RTMP、HTTP-FLV、HLS

甜品

只有严格的工序、精确的用量才能保证甜品如我们预期;只有不断改进烘焙方式和花样才能推陈出新,吸引更多顾客;只有好吃的甜品能够给人愉悦和幸福感。

严格的开发流程

完整的开发流程一般如下:

  • 产品提出需求,内部领导评审。
  • 内部评审通过,拉上 RD、QA、UE 等评审需求、通过后开始详细设计。
  • 评审这些设计比如 RD 的技术方案如何、UI 的视觉设计怎样,其中技术评审往往会让我们对业务风险的把控、技术栈更清晰。
  • 评审结束进行排期、QA 的排期根据 RD、FE的排期而定。
  • 前后端分离开发配合 Mock 数据 + 联调自测。
  • 资深开发进行 Code Review。
  • 邮件提测 QA ,进行各种环境的测试。
  • 产品验收准备上线、准备上线计划:功能点,上线顺序,回滚计划等。
  • 上线后再回测。
  • 第 2 次验收……

面试中/工作中看中的是 ?

  • 价值:你做的东西是否有价值?价值囊括很多方面。

  • 推动力:企业所希望看到的,升职加薪的必要条件。

  • 社区产出:提高你的社会影响力,可能创造无限可能的未来。这一块大厂似乎很看重,有没有道友现身说法的 ?

就像简历中我们所写的:将某个项目的首屏加载提高了 x 倍,在 LCP、FID、CLS 等核心指标上又优化减少了多少秒;今天将软件运行优化得趋于原生体验;明天又产出了某个自研脚手架,提高 x 倍的开发效率;还有社区贡献,影响力...这些都是价值,或者说亮点。

价值在企业招聘中,比重很大,关乎你的未来钱途。甚至间接影响你的身体状况。

别不信,举个例子:程序员,避免不了每天面对新的需求,但是工作内容都是那样,重复又重复,如果一味莽干,免不了要加班、要秃头,占用多少自己的时间和生命?所以一个具有高价值、高优先级的东西,就是提效工具。

有些老油子可能会说:工作都那么忙了,业务需求频繁变更,哪来的时间?我只能轻蔑一笑,呵呵,时间如乳 go&%f3h,挤挤总是会有的。

一个提效工具能挽救多少业务、多少根头发,多少对情侣,相信几年之后,诸君会深有体会。

总结:优先做重要不紧急的事情:个人/团队规划、提效工具/平台建立、锻炼身体/个人影响力建立。事情是做不完的,只需要保证最重要的事情一直在被推进,不重要的可以讨论/推掉/改方案,最后还有一点,就是持续反思,反思可以让你进步飞快。

我的梦想很多,但姑且沉下心来,先实现当前这一个。

早些时候参加了个线下峰会,当时看着一群大佬轮流在台上技术分享,都是一些非常有意思的干货内容,整场下来我的状态是:吃鲸...兴奋...崇拜...

这就是前端吗 ?i 了 i 了,于是额前绑上奋斗的 “奋”,一头莽进了这行。

转眼 0202!

入行这几年,大部分时光都是平淡无奇的,我本来就是个平凡、温和、闷骚、咸鱼的人……常驻知乎、掘金等社区却一直潜水不起一点波纹。

某个时刻,我阅读到 神三元 的系列文章,起初觉得干货满满,嗯,这是个大佬,关注了,每次阅读完他的文章我都淡定地喝一口茶,感觉获益良多。

疫情期间,他又有产出,我照例翻出一览,良久,我喝了口茶,随后眉头一皱,顿觉不对,看下标题,春招?……噗!我震惊,不确定,然后欣喜,沮丧……

这!这居然是一个大三学生,我 &$%^@,大三就进了字节互娱架构组,了不起,恭喜你……

没有比较就没有伤害,想想自己……emmm,原来我是个假前端!

神三元早早就明确了未来目标,就像他文章中说的,找到了痛点。而我们大多数人直到工作了,还很迷茫。就像女生刷 Fit 视频,看到视频里的健身达人曲线姣好的身材,羡慕不已。但看完视频,却只是简单地在床上翻了个身给予回应,甚至还照常打开某团点了杯奶茶。

呵呵,我不想再这样了,现在,先完成 那个 目标吧!

写给未来的我和你们……