Skip to content

Commit

Permalink
feat: add push
Browse files Browse the repository at this point in the history
  • Loading branch information
niaogege committed May 21, 2024
1 parent ab07d3f commit 394a641
Show file tree
Hide file tree
Showing 8 changed files with 1,027 additions and 4 deletions.
293 changes: 293 additions & 0 deletions docs/interview/experiences/0520.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
---
title: 20240520积累面试
order: 37
group:
order: 11
title: /interview/experience
nav:
order: 3
title: 'interview'
path: /interview
---

- 熟悉一兩种常见的前端构建工具(Webpack、rollup、vite 等),熟悉 babel 的使用
- 精通 Web 开发技术,对 JavaScript(含 ES2020)、HTML、CSS、DOM、安全等有较深入的理解,需要有微信小程序开发经验,必须熟悉 typrscript 开发。
- 5 年及以上开发经验,2 年以上 React 开发经验,
- 熟悉基础的算法实现。链表/hash/回溯/深度/广度/dp 动态规划

- 宏任务和微任务 浏览器事件循环
- esmodule 和 commjs 区别
- H5 性能优化和小程序性能优化

## 宏任务和微任务 浏览器事件循环

- 整体的 script 作为第一个宏任务开始执行,执行的时候代码分为同步任务和异步任务
- 同步任务一次进入执行栈一次执行,然后出栈
- 异步任务又分为宏任务和微任务,首先说宏任务
- 宏任务进入到**event Table**中事件表中,并在里面注册回调函数,每当指定的事件完成时,event table 会将这个函数移入到 event queue 中
- 微任务注册要执行的函数,
- 当主线程内的任务执行完毕,执行栈为空的时候,会优先检查微任务的 event queue 是否有事件回调,如果有事件回调则继续执行,没有则执行下一个宏任务
- 上述过程会不断重复,这就是 Event Loop,比较完整的事件循环

## webRTC 了解多少

- 实时通讯技术,允许网络应用建立点对点连接,实现视频流和音频流实时 点对点进行传输,直播业务比较合适
- 三部分组成,浏览器 API+音视频引擎+网络 I/O 协议还有一个就是信令服务器
- 交互过程: 1.音视频采集 2.信令交互,阔以使用 Node 搭建信令服务器 3.创建**RTCPeerConnection** 对象,进行媒体协商

RTCPeerConnection 是一个由本地计算机到远端的 WebRTC 连接,该接口提供**创建,保持,监控,关闭连接**的方法的实现,可以简单理解为功能强大的 **socket** 连接。通过**new RTCPeerConnection**即可创建一个 RTCPeerConnection 对象,此对象主要负责与各端建立连接(NAT 穿越),接收、发送音视频数据,并保障音视频的服务质量,接下来要说的端到端之间的媒体协商,也是基于 RTCPeerConnection 对象来实现的。

### 信令服务是干嘛用的

信令可以简单理解为消息,在协调通讯的过程中,为了建立一个 webRTC 的通讯过程,在通信双方彼此连接、传输媒体数据之前,它们要通过**信令服务器**交换一些信息,如加入房间、离开房间及媒体协商等,而这个过程在 webRTC 里面是没有实现的,需要自己搭建信令服务。

可以使用 **Socket.io** 来实现 WebRTC 信令服务器,Socket.io 已经内置了房间的概念,所以非常适合用于信令服务器的创建。

## esmodule 和 commjs 区别

- 值的拷贝和值的引用

CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值

ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

- 静态编译时输出接口和运行时加载

运行时加载: CommonJS 模块就是对象;即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。

编译时加载: ES6 模块不是对象,而是通过 **export 命令显式指定输出的代码**,import 时采用静态命令的形式。即在 import 时可以指定加载某个输出值,而不是加载整个模块,这种加载称为**编译时加载**

## H5 性能优化和小程序性能优化

### H5 性能优化

- 请求资源 CDN 和 dns 预解析
- http2 多路传输
- 减少不必要的 DOM 访问和操作,动画:请求动画帧 + requestIdleCallback
- 路由懒加载
- 合理使用 defer+async 异步加载和解析 js 脚本
- 合理使用 preload/prefetch 预加载关键资源。
- 减少重绘和回流

- 框架层面,引入中间件简化和隔离这些基础设施与业务逻辑之间的细节,只关注业务本身
- 父组件更新,不波及子组件渲染,没有必要的渲染是对性能的极大浪费。合理使用 react.memo/useMemo/useCallback/shouldComponentUpdate/PureComponent
- 遍历数组的时候,记得加上唯一的标记 key
- 使用 Webpack 等打包工具进行代码分割,按需加载模块。

### webpack 性能优化

- 使用 externals 优化 cdn 静态资源
- tree shaking
- 代码分割
- 图片压缩
- 多线程构建
- 按需引入模块 babel-plugin-import

### 微信小程序性能优化

- 使用分包加载:利用微信小程序的分包加载机制,将不常用的页面放在单独的包中。
- 使用插槽 slot 组件抽离
- 减少 data 和 setData,避免频繁调用 setData,合并多次 setData 调用,减少界面重绘次数
- 使用合适的图片格式和压缩图片,利用图片懒加载。
- 合理使用缓存,利用本地缓存(如 wx.setStorageSync)来存储不常变动的数据,减少网络请求
- 合理使用生命周期函数:避免在 onLaunch、onShow 等生命周期函数中执行耗时操作。
- 减少页面的层级和组件嵌套,简化页面结构。
- 优化第三方库,评估和优化第三方库的使用,避免引入不必要的代码。

```js
// 无重复字符的最长子串
function noDup(str) {
if (str.length == 0) return '';
let arr = [];
let max = 0;
for (let i = 0; i < str.length; i++) {
let cur = str[i];
const index = arr.indexOf(cur);
if (index > -1) {
arr.splice(0, index + 1);
}
arr.push(cur);
max = Math.max(max, arr.length);
}
return max;
}

// 二分法
function two(arr, target) {
let left = 0;
let rignt = arr.length - 1;
while (left <= right) {
let mid = left + Math.floor(right - left) / 2;
if (arr[mid] === target) {
return mid;
} else if (arr[mid] > target) {
right = mid - 1;
} else if (arr[mid] < target) {
left = mid + 1;
}
}
return -1;
}

// 链表反转
function reverse(node) {
let pre = null;
let cur = node;
while (cur) {
let next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
// 是否有环
function isCycle(head) {
let m = new Set();
let cur = head;
while (cur) {
if (m.has(cur)) {
return m.get(cur);
}
m.set(cur, cur);
cur = cur.next;
}
return false;
}

// 盛最多水的容器
var maxArea = function (height) {
// 长*宽
let max = 0;
let left = 0;
let right = height.length - 1;
while (left <= right) {
max = Math.max(max, Math.min(height[right], height[left]) * (right - left));
if (height[right] > height[left]) {
left++;
} else {
right--;
}
}
return max;
};

// 有效的括号
// 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
function isValid(s) {
let m = new Map([
[')', '('],
[']', '['],
['}', '{'],
]);
let arr = [];
for (let item of s) {
if (m.has(item) && m.get(item) == arr.slice(-1)) {
arr.pop();
} else {
arr.push(item);
}
}
return arr.length === 0;
}

// 删除链表一个节点
var deleteNode = function (head, val) {
let dummy = {
next: head,
val: 0,
};
let cur = dummy;
while (cur.next) {
if (cur.next.val == val) {
cur.next = cur.next.next;
}
cur = cur.next;
}
return dummy.next;
};
// 二叉树前中后序
function inOrder(node) {
if (node) {
return null;
}
let arr = [];
let dfs = (node) => {
if (node) {
// 根左右
arr.push(node.val);
dfs(node.left);
dfs(node.right);
}
};
return dfs(node);
}
// BFS 根左右 进右左 => 出 左右根
function BFSorder(node, res = []) {
let queue = [];
let cur = node;
while (cur) {
if (cur.left) {
cur = cur.left;
queue.push(cur.left);
} else {
cur = queue.pop();
res.push(cur.val);
cur = cur.right;
}
}
return res;
}

function preOrder(root, res = []) {
if (!root) return res;
var stack = [root];
while (stack.length) {
let cur = stack.pop();
res.push(cur.val);
if (cur.right) {
stack.push(cur.right);
}
if (cur.left) {
stack.push(cur.left);
}
}
return res;
}

// 层序遍历
function BFS(node) {
let queue = [node];
let res = [];
while (queue.length) {
let len = queue.length;
let arr = [];
for (let i = 0; i < len; i++) {
let tree = queue.shift();
arr.push(tree.val);
if (tree.left) {
queue.push(tree.left);
}
if (tree.right) {
queue.push(tree.right);
}
}
res.push(arr);
}
return res;
}

var maxSubArray = function (nums) {
let max = 0;
let sum = 0;
for (let n of nums) {
if (sum > 0) {
sum += n;
} else {
sum = n;
}
max = Math.max(max, sum);
}
return max;
};
```
Loading

0 comments on commit 394a641

Please sign in to comment.